Java – Thread
- Thread란?
자바 프로그램이 동시에 여러 가지 작업을 수행할 수 있게 해주는 것이 Thread이다.
자바에서 Thread를 만드는 방법은 크게 Thread 클래스를 상속받는 방법과 Runnable 인터페이스를 구현하는 방법이 있다.
- Thread 클래스를 상속받는 방법
Thread를 상속 받은 클래스(MyThread1)를 생성하는데, 반드시 run 메소드를 오버라이딩 해야 한다.
그리고 run 메소드에 실행시킬 코드를 작성한다.
여기서는 str을 작은 시간차를 두고 10번 출력하는 코드를 작성했다.
위에서 만든 MyThread1의 인스턴스를 2개 만들었다.
그리고 start 메소드로 두 스레드를 실행시켰다.
결과는 다음과 같이 출력된다.
main end !!!
*
-
*
-
*
*
*
-
*
-
-
-
*
-
*
*
-
*
-
-
두 스레드가 준비 시간이 있어서 메인이 더 먼저 출력되는 모습이었다.
- Runnable 인터페이스를 구현하는 방법
Runnable 인터페이스가 가지고 있는 run 메소드를 구현해야 한다.
그러나 MyThread2는 이전과 다르게 Thread를 상속받지 않았기 때문에 Thread가 아니다.
그러므로 MyThread2 인스턴스를 생성하여 Thread 인스턴스의 생성자에 넣어서 Thread를 생성한다.
그리고 start를 메소드를 호출한다. 결과는 두 경우가 같다.
- Thread와 공유객체
MusicBox 라는 클래스에 3개의 메소드를 만들었다.
int와 MusicBox를 생성자로 갖는 MusicPlayer라는 클래스를 만들었다.
MusicPlayer는 Thread를 상속하기 때문에 run 메소드를 오버라이드 하여 type에 따라 3가지의 메소드를 호출하도록 하였다.
MusicBox의 인스턴스를 만들고 MusicPlayer의 인스턴스 3개를 각각의 생성자를 받아서 만들었다.
결과는 3가지 음악이 랜덤으로 섞여서 10번씩 출력된다.
- 동기화 메소드와 동기화 블록
메소드 앞에 synchronized를 붙여서 공유객체가 가진 메소드가 동시에 호출되지 않도록 할 수 있다.
여러개의 Thread들이 공유객체의 메소드를 사용할 때 메소드에 synchronized가 붙어 있을 경우 먼저 호출한 메소드가 객체의 사용권(Monitoring Lock)을 얻는다.
메소드 앞에 synchronized 를 붙혀서 실행해 보면, 메소드 하나가 모두 실행된 후에 다음 메소드가 실행된다.
해당 모니터링 락은 메소드 실행이 종료되거나, wait()와 같은 메소드를 만나기 전까지 유지된다. 다른 쓰레드들은 모니터링 락을 놓을때까지 대기한다.
synchronized를 붙히지 않은 메소드는 다른 쓰레드들이 synchronized메소드를 실행하면서 모니터링 락을 획득했다 하더라도, 그것과 상관없이 실행된다.
synchronized를 메소드에 붙혀서 사용 할 경우, 메소드의 코드가 길어지면, 마지막에 대기하는 쓰레드가 너무 오래 기다리는것을 막기위해서 메소드에 synchronized를 붙이지 않고, 문제가 있을것 같은 부분만 synchronized블록을 사용한다.
- Thread와 상태제어
쓰레드는 실행가능상태인 Runnable과 실행상태인 Running상태로 나뉜다.
실행되는 쓰레드 안에서 Thread.sleep()이나 Object가 가지고 있는 wait()메소드가 호출이 되면 쓰레드는 블록상태가 된다.
Thread.sleep()은 특정시간이 지나면 자신 스스로 블록상태에서 빠져나와 Runnable이나 Running상태가 된다.
Object가 가지고 있는 wait()메소드는 다른 쓰레드가 notify()나 notifyAll()메소드를 호출하기 전에는 블록상태에서 해제되지 않는다.
wait()메소드는 호출이 되면 모니터링 락을 놓게 된다. 그래서 대기중인 다른 메소드가 실행한다.
쓰레드의 run메소드가 종료되면, 쓰레드는 종료된다. 즉 Dead상태가 된다.
Thread의 yield메소드가 호출되면 해당 쓰레드는 다른 쓰레드에게 자원을 양보하게 된다.
Thread가 가지고 있는 join메소드를 호출하게 되면 해당 쓰레드가 종료될 때까지 대기하게 된다.
- Thread와 상태제어(join)
다음과 같이 0.5초 간격으로 숫자를 출력하는 MyThread5를 만들었다.
join 메소드를 사용하면 해당 쓰레드가 종료될 때까지 기다렸다가 다시 Main의 내용이 실행된다.
결과는 다음과 같다.
- Thread와 상태제어(wait, notify)
wait와 notify는 동기화된 블록안에서 사용해야 한다(synchronized).
wait 메소드를 만나게 되면 해당 쓰레드는 해당 객체의 모니터링 락에 대한 권한을 가지고 있다면 모니터링 락의 권한을 놓고 대기한다.
notify 메소드를 만나게 되면 wait 하고 있던 스레드를 다시 깨우게 된다.
★ 이 강의의 예제가 잘 매칭이 되지 않아 사진을 올리지 않았음 / wait와 notify가 어떤 용도인지는 알겠음.
- Daemon Thread
Daemon이란 보통 리눅스와 같은 유닉스계열의 운영체제에서 백그라운드로 동작하는 프로그램을 말한다.
Daemon Thread를 만드는 방법은 쓰레드에 데몬 설정을 하면 된다.
이런 쓰레드는 자바프로그램을 만들 때 백그라운드에서 특별한 작업을 처리하게 하는 용도로 만든다.
데몬쓰레드는 일반 쓰레드(main 등)가 모두 종료되면 강제적으로 종료되는 특징을 가지고 있다.
while문 조건에 true를 넣어줌으로써 무한루프 안에서 0.5초마다 해당 텍스트를 출력하도록 하는 run 메소드를 작성했다.
Runnable 인터페이스를 구현하는 DaemonThread를 실행하기 위해서 Thread 인스턴스를 생성하고 setDaemon 메소드를 이용해서 데몬쓰레드로 설정했다.
“메인 쓰레드가 종료됩니다.“ 라고 출력되며 메인 메소드가 종료되자 데몬쓰레드도 종료되는 것을 확인할 수 있다.
'Java > Java의 정석' 카테고리의 다른 글
220302 Java - Chapter 3. 연산자(Operator) (0) | 2022.03.02 |
---|---|
220301 Java - Chapter 2. 변수 (0) | 2022.03.01 |
220225 Java - IO (0) | 2022.02.25 |
220224 Java - Date, Calendar, time패키지 (0) | 2022.02.24 |
220223 Java - Collection Framework (0) | 2022.02.23 |