데몬 스레드( daemon Thread)
- 일반 스레드의 작업을 돕는 보조적인 역할을 수행
- 일반 스레드가 모두 종료되면 자동적으로 종료
- 가비지 컬렉터, 자동저장, 화면자동갱신 등에 사용된다
- 무한루프와 조건문을 이용하여 실행 후 대기하다가 특정조건이 만족되면 작업을 수행하고 다시 대기하도록 작성한다
- setDaemon(boolean on)은 반드시 start()를 호출되기 전에 실행
그렇지 않으면 IllegalThreadStateException이 발생
자동 저장 기능 구현 예제
public class ThreadTest08 {
public static void main(String[] args) {
Thread autoSave = new AutoSaveThread();
System.out.println("데몬스레드 여부 : "+autoSave.isDaemon()); // 데몬스레드 여부 : false
// 데몬스레드로 설정하기
// 반드시 start() 메서드 호출 이전에 설정해야 한다
autoSave.setDaemon(true);
System.out.println("데몬스레드 여부 : "+autoSave.isDaemon()); // 데몬스레드 여부 : true
autoSave.start();
try {
for(int i=1; i<=20; i++) {
System.out.println(i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
// TODO: handle exception
}
System.out.println("main 스레드 종료...");
}
}
// 자동 저장하는 스레드 (3초에 한 번씩 자동으로 저장하는 스레드)
class AutoSaveThread extends Thread{
// 작업 내용을 저장하는 메서드
public void save() {
System.out.println("작업 내용을 저장합니다..."); // 저장한다고 가정
}
@Override
public void run() {
while(true) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO: handle exception
}
save();
}
}
}
스레드의 상태
// 스레드의 상태를 출력하는 예제
public class ThreadTest09 {
public static void main(String[] args) {
TargetThread target = new TargetThread();
Thread t = new StatePrintThread(target);
t.start();
}
}
// 스레드 상태의 검사 대상이 되는 스레드
class TargetThread extends Thread {
@Override
public void run() {
long k = 0;
for (long i = 1L; i <= 20_000_000_000L; i++) {
k = k + 1;
}
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
// TODO: handle exception
}
k = 0;
for (long i = 1L; i <= 20_000_000_000L; i++) {
k = k + 1;
}
}
}
// 검사 대상 스레드의 상태 값을 출력하는 스레드
class StatePrintThread extends Thread {
private TargetThread target;
// 생성자 (초기화)
public StatePrintThread(TargetThread target) {
this.target = target;
}
@Override
public void run() {
Thread.State state = null;
long startTime = 0L;
long endTime = 0L;
while (true) {
// 스레드의 상태값 구하기 ==> getState()메서드 이용
// 스레드의 상택값은 enum(열거형)으로 선언되어있다.
if (state != target.getState()) {
if (startTime != 0L) {
endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
state = target.getState();
System.out.println("TargetThread의 상태 값 : " + state);
startTime = System.currentTimeMillis();
}
if (state == Thread.State.NEW) {// 스레드 상태가 NEW 상태이면
target.start(); // 검사 대상 스레드 실행
}
if (state == Thread.State.TERMINATED) {
break; // 반복문 탈출
}
// try {
// Thread.sleep(500);
// } catch (InterruptedException e) {
// // TODO: handle exception
// }
}
}
}
TargetThread의 상태 값 : NEW
0
TargetThread의 상태 값 : RUNNABLE
4387
TargetThread의 상태 값 : TIMED_WAITING
1515
TargetThread의 상태 값 : RUNNABLE
4386
TargetThread의 상태 값 : TERMINATED
yield()메서드
다른 스레드에게 실행을 양보하는 메서드
import java.io.ObjectInputStream.GetField;
public class ThreadTest10 {
public static void main(String[] args) {
YieldTest th1 = new YieldTest("1번 스레드");
YieldTest th2 = new YieldTest("2번 스레드");
th1.start();
th2.start();
try {
Thread.sleep(10); // 일시정지
} catch (InterruptedException e) {
// TODO: handle exception
}
System.out.println("--------------------------------------------111");
th1.work = false;
try {
Thread.sleep(10); // 일시정지
} catch (InterruptedException e) {
// TODO: handle exception
}
System.out.println("--------------------------------------------222");
th1.work = true;
try {
Thread.sleep(10); // 일시정지
} catch (InterruptedException e) {
// TODO: handle exception
}
System.out.println("--------------------------------------------333");
th1.stop = true;
th2.stop = true;
}
}
// yield() 메서드 연습용 스레드
class YieldTest extends Thread{
public boolean stop = false;
public boolean work = true;
// 생성자
public YieldTest(String name) {
super(name); // 부모의 생성자 호출 (Thread) - 스레드의 이름 설정하기
}
@Override
public void run() {
while(!stop) {
if(work) {
// this.getName()과 같음 > Thread 부모 클래스에 있는 것
System.out.println(getName() + " 작업 중...");
} else {
System.out.println(getName() + " 양보...");
Thread.yield(); // 아무 작업이 없을 시 사용 - 다른 스레드에게 실행 양보
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO: handle exception
}
}
}
}
예제
3개의 스레드가 각각 알파벳을 A~Z까지 출력하는데 출력이 끝낸 순서대로 결과를 나타내는 프로그램 작성하기
import java.util.Random;
public class ThreadTest11 {
public static void main(String[] args) {
DisplayCharacter[] disArr = new DisplayCharacter[] { new DisplayCharacter("신짱구"), new DisplayCharacter("김철수"),
new DisplayCharacter("신짱아") };
for (DisplayCharacter dis : disArr) {
dis.start();
}
for (DisplayCharacter dis : disArr) {
try {
dis.join();
} catch (InterruptedException e) {
// TODO: handle exception
}
}
System.out.println();
System.out.println("\t경기 결과");
System.out.println("순 위 : " + DisplayCharacter.strRank);
}
}
// A ~ Z까지 출력하는 스레드
class DisplayCharacter extends Thread {
public static String strRank = ""; // 작업을 끝낸 순서대로 이름이 저장될 변수
private String name;
// 생성자
public DisplayCharacter(String name) {
this.name = name;
}
@Override
public void run() {
for (char c = 'A'; c < 'Z'; c++) {
System.out.println(name + "의 출력 문자 : " + c);
try {
Thread.sleep(new Random().nextInt(500));
} catch (InterruptedException e) {
// TODO: handle exception
}
}
System.out.println(name + "의 출력 작업 끝...");
// 출력이 끝난 스레드의 이름을 strRank변수에 추가한다
strRank += name + " ";
}
}
stop() / interrupt()
package kr.or.ddit.basic;
/*
* Thread의 stop()메서드를 호출하면 해당 스레드가 바로 멈춘다.
* 이 때 사용하던 자원을 정리하지 못하고 프로그램이 종료되어 다른 프로그램에 영향을 줄 수 있다
* 그래서 stop()메서드는 비추천으로 되어있다
*/
public class ThreadTest13 {
public static void main(String[] args) {
// ThreadStopTest01 th1 = new ThreadStopTest01();
// th1.start();
//
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO: handle exception
// }
//// th1.stop();
// th1.setStop(true); // 프로그램 자체에서 정지
// interrupt() 메서드를 이용한 스레드 멈추기
ThreadStopTest02 th2 = new ThreadStopTest02();
th2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO: handle exception
}
th2.interrupt();
// 일시정지상태에서 interrupt() 메서드가 실행되면 interruptedException발생
}
}
// 스레드를 멈추게하는 연습용 스레드
class ThreadStopTest01 extends Thread {
private boolean stop;
public void setStop(boolean stop) {
this.stop = stop;
}
@Override
public void run() {
while (!stop) {
System.out.println(" 스레드 실행 중...");
// ....
// ...
}
System.out.println("자원정리...");
System.out.println("스레드 종료...");
}
}
// interrupt() 메서드를 이용하여 스레드를 멈추게 하는 방법
class ThreadStopTest02 extends Thread {
@Override
public void run() {
// 방법1 ==> interrupt메서드와 sleep메소드를 이용한 방법
// try {
// while (true) {
// System.out.println("Thread 실행중...");
// Thread.sleep(1);
// }
// } catch (InterruptedException e) {
// // TODO: handle exception
// }
// 방법2 ==> interrupt()메서드가 호출되었는지 검사하는 메서드를 이용하는 방법
while(true) {
System.out.println("스레드 작업중");
// 검사방법1 ==> Thread의 인스턴스 메서드인 isInterrupted()메서드 이용하기
// isInterrupted()메서드는 interrupt()메서드가 호출되면 true를 반환한다
// if(this.isInterrupted()) {
// break;
// }
// 검사방법2 ==> Thread의 정적메서드인 interrupted()메서드 이용하기
// 이 메서드도 interrupt()메서드가 호출되면 true를 반환한다
if(Thread.interrupted()) {
break;
}
}
System.out.println("자원정리...");
System.out.println("스레드 종료...");
}
}
'JAVA > HIGH JAVA' 카테고리의 다른 글
[JAVA] 스레드 - 공통 객체 / 동기화 (1) | 2024.05.01 |
---|---|
4/30 Homework - 경마 프로그램 (0) | 2024.04.30 |
4/29 Homework - 가위바위보 게임 (0) | 2024.04.29 |
[JAVA] 스레드 (0) | 2024.04.29 |
[JAVA] 매개변수, 제네릭, enum (0) | 2024.04.26 |