데몬쓰레드란?
데몬쓰레드 : 일반 쓰레드의 작업을 돕는 보조적인 역할을 수행한다.
일반쓰레드가 종료되면 데몬 쓰레드는 강제적으로 자동 종료된다.
즉 데몬쓰레드가 아닌 쓰레드가 종료되면 데몬쓰레드는 모두 종료된다.
어떤 쓰레드가 대표적으로 사용되는가?
가비지 컬렉터, 자동저장, 화면, 자동갱신 등
쓰지않는 메모리를 제거하거나, 워드에서 자동저장(시간이 셋팅되어있으면), 화면 자동갱신(자동 새로고침 등)
그럼 데몬쓰레드는 어떻게 작성하는가?
public void run() {
while(true)
try{
Thrad.sleep(3*1000); //3초마다
}catch(InterruptedException e) {}
//autoSave값이 true면 autoSave()를 호출한다.
if(autoSave){
autoSave();
}
}
}
무한 루프와 조건문을 이용해서 작성한다. 왜냐하면 언제 끝날지 모르니까.
무한 루프라도 해서 진짜 영원히 함께하는게 아니고 일반메서드가 종료되면 같이 종료되니까 문제는 없다.
그래서 데몬 쓰레드를 작성하는 패턴은 저렇데 되어있다.
(무한루프 + 조건문) - 무한루프니까 중간중간 쉬는시간도 준다.
쓰레드를 데몬쓰레드로 만드는건 아주쉽다.
boolean isDaemon() //쓰레드가 데몬 쓰레드인지 확인한다. 데몬이면 true
void setDaemon(boolean on) //쓰레드를 데몬쓰레드로 또는 사용자 쓰레드로 변경, 매개변수 on을 true로 지정하면 데면 쓰레드가 된다.
setDeamon을 쓰면 그쓰레드가 데몬쓰레드가 된다.
그리고 이건 만드시 start()를 호출하기 전에 실행되어야한다.!!
start()가 호출된 다음에는 데몬쓰레드를 일반으로라던지, 일반을 데몬쓰레드로 바꾼다라 던지 할 수가 없다.
기본적으로 일반쓰레드로만드는게 기본값이긴하다.
package ch13.Thread;
public class ThreadEx10 implements Runnable {
static boolean autoSave = false;
public static void main(String[] args) {
// TODO Auto-generated method stub
Thread t = new Thread(new ThreadEx10());
t.setDaemon(true);
t.start();
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println(i);
if (i == 5) {
autoSave = true;
}
}
System.out.println("작업을 종료합니다.");
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
Thread.sleep(3 * 1000);
} catch (InterruptedException e) {
}
if (autoSave) {
autoSave();
}
}
}
public void autoSave() {
System.out.println("작업내용이 자동저장 되었습니다.");
}
}
클래스를 runnable로 구현했다. 쓰레드 생성자를 제공한다.
runnable 인터페이스가 구현된 run매서드를 작성해서 쓰레드생성자에 전달 하란얘기다.
쓰레드 생성방식 중 다른 하나에 해당하는 방법이다.
1. 쓰레드 클래스를 상속
2. Runnable interface를 구현
run이란 매서드를 가지고있는 클래스의 객체를 매개변수로 넘겨주어서 생성
그리고 setDeamon을 통해 데몬쓰레드로 만들었다.
start()전에 만들었다!
3초마다 자동저장하게 만들었다.
그리고 for문을 도는 동안 i==5전까진 즉
5초가 되기전까지는 autoSave()가 false여서 , autoSave가 실행되지 않게 했다.
그리고 마지막 main쓰레드가 종료되면서 더이상 자동저장이 되지않는다 = 데몬쓰레드도 종료!
데몬쓰레드는 일반쓰레드의 보조역할이니 main메서드가 끝나서 종료된것이다.
만약 setDeamon을 주석처리해서 실행해 본다면?!
그럼 끝도없이 ,, 사용자가 손수 꺼주지 전까지 계속 저장되고있다.
package ch13.Thread;
import java.util.Iterator;
import java.util.Map;
public class ThreadEx11 {
public static void main(String[] args) throws Exception {
ThreadEx11_1 t1 = new ThreadEx11_1("Thread1");
ThreadEx11_2 t2 = new ThreadEx11_2("Thread2");
t1.start();
t2.start();
}
}
class ThreadEx11_1 extends Thread {
ThreadEx11_1(String name) {
super(name);
}
public void run() {
try {
sleep(5 * 1000);
} catch (InterruptedException e) {
}
}
}
class ThreadEx11_2 extends Thread {
ThreadEx11_2(String name) {
super(name);
}
public void run() {
Map<?, ?> map = getAllStackTraces();
Iterator<?> it = map.keySet().iterator();
int x = 0;
while (it.hasNext()) {
Object obj = it.next();
Thread t = (Thread) obj;
StackTraceElement[] ste = (StackTraceElement[]) (map.get(obj));
System.out.println("[" + ++x + "] name : " + t.getName() + ", group : " + t.getThreadGroup().getName()
+ ", daemon : " + t.isDaemon());
for (int i = 0; i < ste.length; i++) {
System.out.println(ste[i]);
}
System.out.println();
}
}
}
getAllStackTreaces()를 이용하면 실행 중 또는 대기상태, 즉 작업이 완료되지 않은 모든 쓰레드의 호출스택을 출력하도록 했다.
새로생성한 쓰레드 t1, t2를 포함해 모두 6개의 쓰레드가 실행 중 또는 대기상태에 있다는 것을 알 수 있다.
프로그램을 실행하면
JVM은 가비지 컬렉션, 이벤트처리, 그래픽처리와 같이 프로그램이 실행되는데 필요한 보조작업을 수행하는 데몬 쓰레드들을 자동적으로 생성해서 실행시킨다.
이들은 system쓰레드 그룹 또는 main쓰레드 그룹에 속한다.
AWT나 swing같은 Gui를 가진 프로그램을 실행하는 경우에는 이벤트와 그래픽처리를 위해 더 많은 수의 데몬 쓰레드가 생성된다.
쓰레드의 상태
쓰레드 프로그래밍이 어려운 이유는 동기화 스케줄링 때문이다.
우선순위를 통해 쓰레드간의 스케줄링을 하는 방법을 배웠지만 효율적인 멀티 쓰레드 프로그램을 만들위 해서는 정교한 스케줄링을 통해 프로세스에게 주어진 자원과 시간을 여러 쓰레드가 낭비없이 잘사용 되도록 해야한다.
그래서 쓰레드의 상태에 대해 알아보자
상태 | 설명 |
NEW | 쓰레드가 생성되고 아직 start()가 호출되지 않은 인 상태 (생성만 된 상태) |
RUNNABLE | 실행 중 또는 실행 가능한 상태 (start를 호출,start했다고 시작되는건아니고 줄서기는 해야함) 왜냐하면 먼저온 쓰레드들이있으니까 순서는 지켜야함, 그러다 자기차례가되면 실행되게된다. 그러다 자기차례끝나면 다시 돌아간다. - 작업이 모두 끝날때까지 반복한다. 모두 종료된다면 소멸된다. |
BLOCKED | 동기화 블럭에 의해서 일시정지된 상태(lock이 풀릴 때까지 기다리는 상태) |
WAITINGM TIMED_WAITING |
쓰레드의 작업이 종료되지 않았지만 실행가능 하지않은 (unrunnable) 일시정지 상태, TIMED_WAITING은 일시정지기간(시간)이 지정된 경우를 의미(쉼터, 대기실) |
TERMINATED | 쓰레드의 작업이 종료된 상태 |
처음에 쓰레드 생성 -> start호출-> 줄서다가 -> 실행 -> 반복 -> 자기의 작업이 끝나거나 stop()매서드에 의해 소멸!
쓰레드가 중간중간 멈출떄가 있다.
그네를 탄다고 예를들자, 그네에 앉아서 그네를 타는데 사람이 많아 뒤에, 그래서 조금밖에 못타고 다시 내려서 줄선다...
그러다 순서가 오면 다시타고 내리고 반복하다가 하나둘씩 작업들이 종료되어지고, 내차례도 빈번하게 올때쯤 나도 작업종료해서 더이상 그네를 타지않는 그렇게 이해하면 편하겠다. 또는 벤치로 가서 잠시 쉬는 것(waiting, blocked)을 하고 다시 탈 수 도있다.
쓰레드의 실행제어
쓰래드의 실행을 제어할 수 있는 메서드가 있다.
static void sleep() | 지정된 시간동안 쓰레드를 일시정지, 지정한 시간이 지나고 다시 실행 대기 상태가 된다. |
void join() | 다른 쓰레드가 작업이 종료되기를 기다린다. 지젖ㅇ된 시간동안 쓰레드가 실행되도록 한다. 지정된 시간이 지나거나 작업이 종료되면 join을 호출한 쓰레드로 다시 돌아와 실행을 계속한다. |
void interrupt() | 깨우는것, 자고있는걸 깨우던가, join된걸, 기다리는걸 깨워서 일시정지 상태를 벗어나게 한다. |
void stop() | 쓰레드를 즉시 종료시킨다. |
void suspend() | 알사종자 사칸더, resume 를 호출하면 다시 실행 대기 상태가된다. |
void resume() | suspend에 의해 일시정지 상태에 있는 쓰레드를 실행대기 상태로 만든다. |
static void yeild() | 실행중에 자신에게 주어진 실행시간을 다른쓰레드에게 양보하고 자신은 실행대기 상태가 된다. 작업을 하다가 양보해주는것 그리고 자시는 일시 상태가된다. |
sleep 이랑 yeild는 스태틱이 붙어있다. 즉 쓰레드 자기자신에게만 호출이 가능하다.
그 외에는 다른 쓰레드를 제어할 수 있지만, static이 붙은 제어문은 본인 쓰레드에서만 작동이 가능하다 .
'JAVA공부 > 2-쓰레드' 카테고리의 다른 글
쓰레드 제어문(1) (0) | 2021.10.13 |
---|---|
쓰레드 제어문(1) (0) | 2021.10.13 |
쓰레드의 우선순위, 그룹 (0) | 2021.10.12 |
싱글쓰레드와 멀티쓰레드 (0) | 2021.10.08 |
쓰레드의 구현과 실행 (0) | 2021.10.07 |
댓글