🎯 목표 : 쓰레드의 활용 이해
📒 Thread
📌 Thread의 우선순위
- 작업의 중요도에 따라 쓰레드의 우선순위를 다르게 하여 특정 쓰레드가 더 많은 작업시간을 갖게 할수있다.
- 우선순위를 정의하게 되면, 쓰레드를 생성한 쓰레드로 부터 상속받는다. main 메소드를 동작하게 하는 쓰레드는 기본 우선순위가 5이며, main 메소드 내에서 생성한 쓰레드는 모두 기본값 5를 가지고 동작한다.
- 정의한 우선순위보다 OS 스케쥴러의 우선순위가 더 우선되기 때문에 정확하지 않다.
📌 Thread 그룹
- 서로 관련된 쓰레드를 그룹으로 묶어서 다룬다
- 모든 쓰레드는 반드시 하나의 쓰레드 그룹에 포함되어 있다.
- 쓰레드 그룹을 지정하지 않으면 main 쓰레드 그룹에 속하게 된다.
- 자신이 생성한 쓰레드(부모 쓰레드)의 그룹과 우선순위를 상속받는다.
- 쓰레드 그룹과 관련된 메소드를 가지고 다룰수 있다.
📌 데몬 쓰레드(Daemon Thread)
- 쓰레드는 일반 쓰레드와 데몬 쓰레드로 나뉜다.
- 일반 쓰레드의 작업을 돕는 보조적인 역할을 하는게 데몬 쓰레드다.
- 예를들면 Garbage Colletor, 자동 저장, 화면 자동갱신 등이 있다.
- 무한 루프 반복문과 조건문으로 실행후 대기하다가 특정 조건에 부합하면 작업을 수행하고 다시 반복하며 대기하도록 작성한다.
- setDaemon(true)를 호출하여 데몬 쓰레드를 실행하는데, 반드시 일반쓰레드를 실행하기 전에 호출해야한다.
👉 예제
public class DaemonThreadStudy implements Runnable {
static boolean autoSave = false;
public static void main(String[] args) {
Thread t = new Thread(new DaemonThreadStudy()); // 쓰레드 생성
t.setDaemon(true); //setDaemon 은 쓰레드 실행 전에 호출해야된다.
t.start(); // 데몬 쓰레드 동작 시작
for(int i=1; i <= 10; i++) { // 1초에 하나씩 증가하도록 설정
try{
Thread.sleep(1000);
} catch(InterruptedException e) {}
System.out.println(i);
if(i==5) autoSave = true;// i 의 값이 5가 될때 true가 되며 데몬 쓰레드가 동작한다.
}
System.out.println("종료");
}
public void run() {
while(true) {
try {
Thread.sleep(3 * 1000); // 위 i 의 값이 5이후에는 3초마다 동작한다
} catch(InterruptedException e) {}
// autoSave의 값이 true 일때 autoSave()메소드를 호출한다.
if(autoSave) autoSave();
}
}
public void autoSave() {
System.out.println("자동 저장됨...");
}
}
- 위 예제에서 만약 쓰레드 t를 setDaemon호출하여 데몬 쓰레드로 만들지 않았다면, 이 예제의 run메소드 부분의 무한 반복문이 멈추지 않고 계속 돌게 될것이다. 데몬 쓰레드는 일반 쓰레드가 동작이 모두 끝나게 되면 함께 종료된다는 것을 확인할수 있다.
📌 Thread의 상태와 실행제어

- 위 그림으로 쓰레드 들이 생성되고 실행되거나, 대기 상태가 되는 쓰레드 들의 상태 변화를 알수 있다.
- start 메소드는 쓰레드를 실행 시키는 메소드가 아닌 실행 대기 상태로 만들어주는 메소드다.
- 쓰레드의 실행과 대기를 제어할수 있는 메소드가 있으며 이를 활용해 효율적인 프로그램을 작성 할수있다.
- static 메소드는 쓰레드 자기 자신에게만 호출 가능하다.

👉 sleep()
- 지정 시간동안 쓰레드를 멈추게한다.
- sleep에 의해 일시 정지된 쓰레드는 시간이 다 되거나, interrupt가 호출되면 InterruptedException이 발생하며 깨어나서 실행대기 상태가 된다 위 데몬 쓰레드 예제에서 확인할수 있다.
- 예외 처리를 해줘야한다. 아래와 같이 메소드를 만들어 활용할수도 있다.
void sleepTh(long millis) {
try {
Thread.sleep(millis);
} catch(InterruptedException e) {}
}
👉 interrupt() , interrupted()
- 쓰레드의 작업을 취소한다.
- 대기상태인 쓰레드를 실행 대기 상태로 만든다.
void interrupt() // 쓰레드의 interrupted 상태를 false에서 true로 변경
boolean isInterrupted() // 쓰레드의 interrupted 상태를 반환.
static boolean interrupted()// 현재 쓰레드의 interrupted 상태를 반환 후 false로 변경
2022.09.04 - [Language/JAVA] - Java Thread_01 의 멀티 쓰레드 예제를 수정하여 interrupt를 학습했다.
Java Thread_01
🎯 목표 : 프로세스와 쓰레드의 개념을 이해하고 Java에서 쓰레드의 활용을 이해 📒 Process, Thread 📌 프로세스는 공장 쓰레드는 일꾼 프로세스는 실행중인 프로그램 자원과 쓰레드로 구성되어있
sussa1933.tistory.com
import javax.swing.*;
public class ThreadStudy3 {
public static void main(String[] args) throws Exception {
Thread1 th1 = new Thread1();
th1.start();
String input = JOptionPane.showInputDialog("입력하세요");
System.out.println("입력값 : " + input );
th1.interrupt();
System.out.println("isInterrupted의 값 = "+th1.isInterrupted());
}
}
class Thread1 extends Thread {
public void run() {
int i=10;
while (i!=0&&!isInterrupted()){
System.out.println(i--);
for(long x=0; x<2500000000L; x++);
}
System.out.println("종료");
}
}
- 쓰레드가 실행되고 input값을 입력하지 않으면 run() 메소드의 while 문은 계속 흘러간다.
- input값을 입력하고 interrupt()가 호출되면, isInterrupted()의 값은 true가 되고, run()의 while문도 종료된다.
====출력값====
10
9
8
7
6
5
입력값 : 1234
isInterrupted의 값 = true
종료
👉 yield()
- 남은시간을 다음 쓰레드에게 양보하고 자기 쓰레드(static)는 실행 대기.
while (true){
if(!isInterrupted()){
System.out.println(t--);
try{
Thread.sleep(10000);
} catch(InterruptedException e) {
interrupt();
break;
}
}
}
- 위의 예제에서 쓰레드는 sleep의 호출로 인하여 10초 동안 실행을 멈춤상태가 되고 10초 동안에도 while문은 isInterrupted의 값이 true가 될때까지 의미없이 계속 반복한다. 이런 상태를 바쁜 대기상태(busy-waiting)라고 하며 yield를 호출해서 남은 실행시간을 반복문에서 낭비하지 않고 다른 쓰레드에게 양보하게 된다.
while (true){
if(!isInterrupted()){
System.out.println(t--);
try{
Thread.sleep(10000);
} catch(InterruptedException e) {
interrupt();
break;
}
} else { Thread.yield(); }
}
👉 join()
- 다른 쓰레드의 작업을 기다린다.
- 쓰레드 자신이 하던 작업을 잠시 멈추고 다른 쓰레드가 지정된 시간동안 작업을 수행하도록 할때 join()을 사용한다.
- 매개 변수 (long millis) (long millis, int nanos) 로 시간을 지정하지 않으면 작업을 끝낼때 까지 기다리게 된다.
- 데몬 쓰레드와 멀티 쓰레드의 복합적인 예제를 만들어 학습했다.
public class ThreadStudy2 {
static long startTime = 0;
public static void main(String args[]) {
ThreadEx_1 th1 = new ThreadEx_1();
ThreadEx_2 th2 = new ThreadEx_2();
Thread dt1 = new Thread(new Daemon_1());
dt1.setDaemon(true);// setDaemon 은 시작 전에 호출해야된다.
dt1.start(); // 데몬 쓰레드 동작 시작
th1.start();
th2.start();
startTime = System.currentTimeMillis();
try {
th1.join(); // th1 끝날때 까지 기다린다.
System.out.println("////");
} catch(InterruptedException e) {}
try {
th2.join(); // th2 끝날때 까지 기다린다.
System.out.println("@@@@");
} catch(InterruptedException e) {}
System.out.println("Time :" + (System.currentTimeMillis() - ThreadStudy2.startTime));
} // main
}
class ThreadEx_1 extends Thread {
public void run() {
for(int i=0; i < 20; i++) {
try{
Thread.sleep(300);
} catch(InterruptedException e) {}
System.out.print("*");
if(i==5) Daemon_1.autoSave =true;
}
}
}
class ThreadEx_2 extends Thread {
public void run() {
for(int i=0; i < 30; i++) {
try{
Thread.sleep(300);
} catch(InterruptedException e) {}
System.out.print("=");
if(i==5) Daemon_1.autoSave =true;
}
} // run()
}
class Daemon_1 implements Runnable {
public static boolean autoSave = false;
public void run() {
while (true){
try {
Thread.sleep(3*1000);
}catch (InterruptedException e){}
if(autoSave) save();
}
}
public void save() {
System.out.println("자동 저장됨.");
}
}
- ThreadEx_1, ThreadEx_2 일반 쓰레드와 Daemon_1 데몬 쓰레드를 정의하고, main 메소드에서는 멀티 쓰레드가 동작이 끝날때까지 시간을 카운터 하고 있으며, 멀티 쓰레드가 동작을 마치게 되면 카운터 한 시간을 출력하기 위해서 join() 메소드를 활용하여 main 메소드의 동작을 멈추게 했다.
- 데몬 쓰레드는 일반 쓰레드가 동작하면서 3초마다 호출되어 출력하도록 작성하였다.
- 여기서 join() 메소드를 호출하여 main 메소드의 동작을 멈추고 일반 쓰레드가 동작을 마칠때까지 기다리게 해주는 역할을 하고 있다.
- main 메소드에서 join()이 호출되어 동작이 멈춘다는 것은, public 클래스도 하나의 쓰레드로 동작하고 있다는 것을 확인할수 있다.
출력값
=*=*=**=*=*=*=*=*=자동 저장됨.
=*=*=*=*=**==*=*=**=자동 저장됨.
*=//// <- ThreadEx_1 종료
=========자동 저장됨.
=@@@@ <- ThreadEx_2 종료
Time :9283 <- 모두 종료 후 출력
- 출력값을 보면, ThreadEx_1이 종료되고, 호출한 th1.join() 메소드 다음줄의 코드가 실행된 것을 볼수 있다.
- ThreadEx_1 쓰레드가 종료되고 , th1.join() 메소드가 실행 될때까지 main 메소드가 멈춰 있었던 것을 확인할수 있다.
'Language > JAVA' 카테고리의 다른 글
| Java Lambda Expression(람다식)_01 (1) | 2022.09.07 |
|---|---|
| Java Thread_03 (0) | 2022.09.05 |
| Java Thread_01 (0) | 2022.09.04 |
| Java Annotation (1) | 2022.09.04 |
| Java 열거형 (0) | 2022.09.03 |