쓰레드의 상태는 .getState() 메서드를 호출해 확인할 수 있다.
| 상태 | 설명 |
|---|---|
| NEW | 쓰레드가 생성되고 아직 start()가 호출되지 않음 |
| RUNNABLE | 실행 중 또는 실행 가능함 |
| BLOCKED | 동기화블럭에 의해 일시정지됨 (lock이 풀릴때까지 대기상태) |
| WAITING, TIMED_WAITING | 작업이 종료되지는 않았지만, 일시정지된 상태. TIMED_WAITING 은 일시정지시간이 지정된 경우 |
| TERMINATED | 작업이 종료된 상태 |
sleep() : 일정시간동안 쓰레드를 멈춘다.
try{
Thread.sleep(1000); // 쓰레드를 1초동안 멈춘다. (밀리세컨드)
} catch(InterruptedException e){}
sleep을 호출할 때는 항상try-catch문으로 예외처리를 해줘야 하는데, 매번 예외처리를 하기엔 번거롭기 때문에 아래와 같이 메서드를 만들어서 사용하는 것이 좋다.// 예외처리를 한 메서드를 만들어둠 void delay(long millis){ try{ Thread.sleep(millis); }catch(InterruptedException e){} } // 사용할 때 delay(1000); // 쓰레드를 1초동안 멈춘다.
sleep() 메서드는 static 으로 선언되어 있으며, 항상 실행중인 쓰레드에 대해 작동한다. 따라서 참조변수를 이용해 호출하기 보다는 Thread.sleep() 으로 사용해야 한다.
쓰레드를 멈추고 다시 시작하는 메서드는
suspend()와resume()도 있지만 하위호환성을 위해 남겨진 메서드일 뿐 더이상 사용하지 않는다.
interrupted() : 쓰레드의 작업을 취소한다.
void interrupt();
boolean isInterrupted();
static boolean interrupted();
interrupt()는 작업을 취소하라고 요청하고 interrupted 상태만 바꿀 뿐 강제로 종료시키지는 못한다.
isInterrupted() 는 쓰레드의 interrupted 상태를 반환한다.
interrupted() 는 쓰레드의 interrupted의 상태를 반환 후 false로 바꾼다.
class Thread1 implements Runnable{
public void run(){
while(!Thread.interrupted()){
System.out.println("false 상태 입니다.");
}
}
}
public class Main{
public static void main(String[] args){
Thread t = new Thread(new Thread1());
t.start();
// 단순 시간 지연을 위한 for문
for(int i=0; i<50000; i++){}
t.interrupt();
if(t.isInterrupted()){
System.out.println("true 상태로 변환되었습니다.");
}
}
}
/*
실행 결과
false 상태 입니다.
false 상태 입니다.
false 상태 입니다.
false 상태 입니다.
false 상태 입니다.
false 상태 입니다.
false 상태 입니다.
false 상태 입니다.
false 상태 입니다.
false 상태 입니다.
false 상태 입니다.
true 상태로 변환되었습니다.
*/
yield() : 다른 쓰레드에게 양보한다.
자신에게 주어진 실행시간을 다음 쓰레드에게 양보한다. 예를 들어, 1초의 실행시간을 할당받은 쓰레드가 0.5초의 시간동한 작업한 상태에서 yield()가 호출되면 나머지 0.5초는 포기한 채 실행대기상태가 되는 것이다.
public class Main{
public static void main(String[] args) {
Thread1 t1 = new Thread1("*");
Thread1 t2 = new Thread1("**");
Thread1 t3 = new Thread1("***");
t1.start();
t2.start();
t3.start();
try{
Thread.sleep(1000);
t1.suspend();
Thread.sleep(1000);
t2.suspend();
Thread.sleep(1000);
t1.resume();
Thread.sleep(1000);
t1.stop();
t2.stop();
Thread.sleep(1000);
t3.stop();
} catch (InterruptedException e){}
}
}
class Thread1 implements Runnable{
boolean suspended = false;
boolean stopped = false;
Thread t;
public Thread1(String name) {
t = new Thread(this, name);
}
public void run(){
String name = t.getName();
while(!stopped){
if(!suspended){
System.out.println(name);
try{
Thread.sleep(1000);
}catch(InterruptedException e){
System.out.println(name + " - interrupted");
}
}else{
Thread.yield();
}
}
System.out.println(name + " - stopped");
}
public void suspend(){
suspended = true;
t.interrupt();
System.out.println(t.getName() + " - interrupt() by suspend()");
}
public void stop(){
stopped = true;
t.interrupt();
System.out.println(t.getName() + " - interrupt() by stop()");
}
public void resume(){
suspended = false;
}
public void start(){
t.start();
}
}
/*
실행 결과
*
**
***
*
***
**
* - interrupt() by suspend()
* - interrupted
***
**
** - interrupt() by suspend()
** - interrupted
***
*
***
*
* - interrupted
* - stopped
* - interrupt() by stop()
** - interrupt() by stop()
** - stopped
***
*** - interrupt() by stop()
*** - interrupted
*** - stopped
*/
위의 코드처럼 interrupt()와 적절하게 사용하면, 응답성을 높이고 보다 효율적인 실행이 가능하다.
join() : 다른 쓰레드의 작업을 기다린다.
void join();
void join(long millis);
작업 중에 다른 쓰레드의 작업이 먼저 수행되어야 할 때 사용한다.
시간을 지정하지 않으면 해당 쓰레드가 작업을 모두 마칠 때까지 기다린다.
public class Main{
static long startTime = 0;
public static void main(String[] args) {
Thread1 t1 = new Thread1();
Thread2 t2 = new Thread2();
t1.start();
t2.start();
startTime = System.currentTimeMillis();
try{
t1.join();
t2.join();
}catch (InterruptedException e){}
System.out.println("소요시간 : " + (System.currentTimeMillis() - Main.startTime));
}
}
class Thread1 extends Thread{
public void run(){
for(int i=0; i<300; i++){
System.out.print("0");
}
}
}
class Thread2 extends Thread{
public void run(){
for (int i=0; i<300; i++){
System.out.print("1");
}
}
}
/*
실행 결과
111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111110111111111111111111000000000000000000000000000000000000000000000000000000000000000000000000소요시간 : 9
*/
위의 코드에서 join() 을 사용해 t1 쓰레드와 t2 쓰레드가 작업을 끝낼 때 까지 main 쓰레드가 기다리도록 했다.
따라서 main 쓰레드가 두 쓰레드 작업에 소요된 시간을 출력할 수 있는 것이다.
join()을 사용하지 않았다면 System.currentTimeMillis()와 Main.startTime이 동일하게 나와 소요시간을 구할 수 없을 것이다.