Java - 기본기

24. Thread - 스레드 다루기(feat. Lotte 번호찍기)

TerianP 2022. 3. 14.
728x90

# 여기서 나오는 JFrame 은 따로 한번 더 정리할 예정입니다!

1. Thread 와 Process

1) Process 프로세스

Thread 를 알기 위해서는 프로세스에 대해서 먼저 이야기하여야한다. 프로세스 - Process - 란 단순하게 이야기해서 실행중인 프로그램 이라고 할 수 있다.

즉, 사용자가 작성한 프로그램이 운영체제에 의해 메모리 공간을 할당받아 실행 중인 것을 말한다. 이러한 프로세스는 프로그램에 사용되는 데이터와 메모리 자원 그리고 스레드로 구성된다.

 

2) Thread 스레드

Thread 스레드란 프로세스 내에서 실제로 작업을 수행하는 주체를 의미한다. 모든 프로세스에서는 한 개 이상의 스레드가 존재하며 작업을 수행한다. 또한 두 개 이상의 스레드를 가지는 프로세스를 멀티 스레드 프로세스(multi - threaded process) 라고 한다 -> 쉽게 그냥 멀티 스레드!

 

2. Thread 의 라이프 사이클

  • 스레드의 라이프 사이클은 위 사진을 참고하면 된다.
  • 먼저 new 를 통해서 스레드가 생성된다.
  • 이후 start() 메소드를 사용하면 Runnable 상태가 된다 => 이 상태는 cpu 로부터 메모리 할당을 기다리는 실행 가능 준비 상태이다.
  • 이후 run() 메소드를 통해서 Running 상태가 된다 => 이 상태에서는 cpu로부터 사용 메모리르를 할당받아 실제 스레드가 실행되는 상태이다. run() 메소드는 단독으로 실행한는 것이 아니라 start() 메소드를 실행 시 Runnable 상태에서 메모리 할당이 되면 알아서 넘어간다.
  • blcoked 상태는 sleep(), wait() 를 사용하여 스레드가 일지 중단이거나, 휴면 중이거나 특정 조건을 충족하기 위해 일정시간을 대기하는 상태라고 생각이다. => 이때 sleep 의 경우에는 sleep 이후 일정시간이 지나면 sleep 에서 깨어나 다시 스레드가 시작되고, wait 의 경우 일시정지 상태로서 notify() 나 notifyAll() 을 통해 일시정지된 스레드를 다시 불러와 실행시키게 된다. 

 

3. Thread 구현 방법

스레드 구현방법은 크게 2가지로 나뉜다.

  1. Thread 클래스를 상속받아서 사용 : 말 그대로 Thread 클래스를 상속받은 후 run() 메소드를 오버라이딩하여 내 맘대로 수정한 후 start() 메소드를 실행하여 스레드를 실행하는 방법이다 => 가장 보편적이고 가장 많이 사용한다.
  2. Runnable 인터페이스를 구현 : Runnable 인터페이스를 구현하여 사용하는 방법이다. 순서는 Runnable 인터페이스를 상속받아 구현하고 이후 Run() 메소드를 오버라이딩한다. 다음으로 Thread 객체를 생성하는데 이때 Thread 의 생성자매개 변수로 Runnable 인터페이스를 구현한 구현 클래스가 오게 된다. 마지막으로 Thread 클래스 인스턴스를 생성후 start() 메소드를 실행한다 => 이렇게 인터페이스를 구현하는 것은 Thread 클래스를 상속받아 사용하기 어려운 경우에 사용하는 방법으로 자주 사용되는 방식은 아니다.

 

4. Thread 갖고 놀기

  • Thread 연습을 위해 구현해볼 게임은 바로 경마 게임이다!!
  • 구현 목표는 다음과 같다.
    • 총 7개의 버튼 - 이 중 6개는 번호를 출력하기 위한 버튼이고 나머지 하나는 게임 시작을 위한 버튼이다.
    • 6개의 버튼은 생성자에 이미지를 넣어줘서 해당 번호 이미지를 버튼 위에 씌우고 버튼을 만든다.
    • 게임 시작버튼에는 액션 이벤트를 달아서 버튼을 눌렀을 때 번호를 출력하는 스레드를 실행한다. 총 6개의 버튼이 있고 이 버튼마다 스레드가 구현됨으로 멀티 스레드로 동작하게 된다.

 

1) lotte클래스

  • JFrame 을 통해 구현한 메인 클래스로 이 클래스를 통해서 윈도우 창이 생성되고, 버튼도 생성된다.
  • lotte() 메서드는 HashSet 을 이용해서 랜덤한 중복값이 없는 번호 배열로 만든다. 이후 배열을 다시 Arrays.sort 매서드로 정렬까지 한 후 해당 배열을 return 한다.
  • lotte 클래스에서 중요한 것은 로또 번호를 밖에서 스레드 클래스인 Lotte05 생성자 매개변수에 넣는다는 점이다. 이는 스레드안에서 lotte 메서드를 통해 로또 번호를 만들게되면 각 스레드마다 로또번호를 만들기 때문에 중복 값이 나올 수도 있고, 번호가 정렬되지 않는다. 이를 해결하기 위해 밖에서 스레드 쪽으로 번호를 보내주게 된다.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Quiz05 extends JFrame {
	JButton[] nBtn = new JButton[6];
	JButton cBtn;
	int[] num;

	JPanel jp = new JPanel();

	ImageIcon img = new ImageIcon("src/lotte/q.png");

	public Quiz05() {

		this.setTitle("로또 추첨기");
		this.setVisible(true);
		this.setBounds(100, 100, 600, 400);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.setLayout(null);

		int btnX = 150;
		for (int i = 0; i < nBtn.length; i++, btnX += 50) {
			nBtn[i] = new JButton(img);
			nBtn[i].setBounds(btnX, 150, 50, 50);
			this.add(nBtn[i]);
		}

		// Click 버튼
		cBtn = new JButton("Click!! 인생은 어짜피 한방");
		cBtn.setBounds(150, 250, 300, 100);
		cBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				int[] lotte = lotte();

				Lotte05_Thread lt01 = new Lotte05_Thread(nBtn[0], lotte[0]);
				lt01.start();
				Lotte05_Thread lt02 = new Lotte05_Thread(nBtn[1], lotte[1]);
				lt02.start();
				Lotte05_Thread lt03 = new Lotte05_Thread(nBtn[2], lotte[2]);
				lt03.start();
				Lotte05_Thread lt04 = new Lotte05_Thread(nBtn[3], lotte[3]);
				lt04.start();
				Lotte05_Thread lt05 = new Lotte05_Thread(nBtn[4], lotte[4]);
				lt05.start();
				Lotte05_Thread lt06 = new Lotte05_Thread(nBtn[5], lotte[5]);
				lt06.start();

			}
		});

		this.add(cBtn);
	}

	int[] lotte() {
		HashSet hs = new HashSet();
		int lotte[] = new int[6];
		Random ran = new Random();

		for (;;) {
			hs.add(ran.nextInt(45) + 1);

			if (hs.size() == 6) {
//				System.out.println("hs : "+hs);
				break;
			}
		}

		Iterator it = hs.iterator();

		for (int i = 0; i < lotte.length; i++) {
			lotte[i] = (int) it.next();
		}

		Arrays.sort(lotte);

		return lotte;
	}

	public static void main(String[] args) {
		new Quiz05();
	}
}

 

2) lotte Thread 클래스

  • 스레드를 상속받아서 스레드가 구현되고 실행되는 클래스이다.
  • 생성자로는 JButton 객체와 lotte() 메서드를 통해서 정해진 로또 번호가 넘어온다.
  • 초기에 랜덤한 값을 계속 나오게 하기 위해서 ranNum 을 만든후 해당 랜덤값과 동일한 png 파일을 가져온다. 이후 생성자로 받아온 jbtn 에 setIcon 매서드를 사용해서 새로운 이미지로 덮어씌우고 이 과정을 for 문이 도는 동안 반복한다.
  • for 문의 반복이 끝나면 Thread.sleep(100) 이 실행된다. 여기서 100은 100ms - 밀리세컨드 -로 0.1 초를 의미한다. 이후 매개변수로 넘어온 lotte 값이 버튼에 넣어지게 되고 화면에 등장하게 된다.
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JButton;

public class Lotte05_Thread extends Thread{
	JButton jbtn;
	ImageIcon img;
	int lotte;
	Random ran = new Random();
	
	public Lotte05_Thread(JButton jbtn, int lotte) {
		// TODO Auto-generated constructor stub
		this.jbtn = jbtn;
		this.lotte = lotte;
	}
	
	@Override
	public void run() {
		
		// 아래 1~3 을 20번 반복
		for(int i=0; i<20; i++) {
			// 1. 랜덤값 추출
			int ranNum = ran.nextInt(45)+1;
			
			// 2. 랜덤값에 해당하는 lotte 그림 선택
			img = new ImageIcon("src/lotte/ball"+ranNum+".png");
			
			// 3. lotte 그림 버튼에 씌우기
			jbtn.setIcon(img);
			
			try {
				// 4. Thread Sleep 가 없다면 그림이 바뀌는 것을 확인 불가
				// 따라서 100ms 즉 0.1 초마다 변하도록
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		try { 
			// 반복이 끝나면 다시 0.1 초 후 정답공개
			Thread.sleep(100);
			
			img = new ImageIcon("src/lotte/ball"+lotte+".png");
			jbtn.setIcon(img);

			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		
	}

}

 

 

 

 


동작 확인

짜잔!! 당신의 행운 번호는...?!


 

- 참고

http://www.tcpschool.com/java/java_thread_concept

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

 

댓글