개요
- 김영한 강사님의 강의를 듣고 정리하였다.
스레드들의 작업을 중간에 중단하려면 어떻게 해야할까?
본론
예제 1
스레드가 Thread.sleep()을 통해 TIMED_WAITING 상태에 있는 경우, 해당 스레드를 깨워야 하는 상황이 있을 수 있다.
- 이 경우에는 어떻게 스레드를 깨울 수 있을까?
Interrupt를 사용하면 WAITING, TIMED_WAITING 같은 대기 상태의 스레드를 RUNNABLE 상태로 깨울 수 있다.
public class ThreadTest{
public static void main(String[] args){
MyTask task = new MyTask();
Thread thread = new Thread(task, "work");
thread.start();
sleep(4000);
thread.interrupt();
}
static class MyTask implements Runnable{
@Override
public void run(){
try{
while(true){
Thread.sleep(3000);
}
} catch(InterruptedException e){
System.out.println(Thread.currentThread().isInterrupted());
}
}
}
}
Thread.sleep() 메서드는 InterruptedException 예외를 던진다.
thread.interrupt()
- 해당 스레드에 interrupt를 발생시킨다.
- 이 메서드를 이용하면 Thread.sleep()을 이용해서 TIMED_WAITING 상태로 들어간 스레드를 RUNNABLE 상태로 바꿀 수 있다.
- 발생 이후 상황은 예외를 잡은 후 작업을 작성해준다.
문제점1
while(true){
Thread.sleep(3000);
}
- 이 코드의 문제점은 while(true) 부분에서는 인터럽트가 발생해도 InterruptedException이 발생하지 않고 Thread.sleep()을 호출할 때 까지 코드는 실행된다.
- 이런 늦은 반응성을 어떻게 해결해줄 수 있을까?
- while(true) 대신에 우리가 직접 Thread의 인터럽트 발생 여부를 확인한다면 해결될 것이다.
예제2
public class ThreadTest{
public static void main(String[] args){
MyTask task = new MyTask();
Thread thread = new Thread(task, "work");
thread.start();
sleep(4000);
thread.interrupt();
}
static class MyTask implements Runnable{
@Override
public void run(){
while(Thread.currentThread().isInterrupted()){
// 작업
}
System.out.println(Thread.currentThread().isInterrupted());
}
}
}
Thread.currentThread().isInterrupted()
- 현재 스레드를 가져와서 isInterrupted() 메서드로 현재 스레드가 인터럽트 상태인지 아닌지 확인할 수 있다.
문제점
isInterrupted()
메서드는 현재 스레드의 인터럽트 상태만 확인할 뿐 인터럽트 상태를 false로 전환하지 않는다.
따라서 이후에 InterruptedException을 발생시키는 코드를 호출할 경우 의도치 않은 예외가 발생할 수 있다.
따라서 우리는 인터럽트를 활용한 후 false로 전환시켜야 한다.
예제3
Thread.interrupted()
- 스레드의 인터럽트 상태를 확인한다면 앞에서 사용한
isInterrupted()
를 사용하면 되지만 직접 인터럽트를 사용하려고 한다면 interrupted() 메서드를 사용해야 한다.
인터럽트가 발생한 경우 : true를 반환하고 인터럽트 상태를 false로 전환한다.
인터럽트가 발생하지 않은 경우 : false를 반환하고 인터럽트 상태를 유지한다.
@Override
public void run(){
while(Thread.interrupted()){
// 작업
}
System.out.println(Thread.currentThread().isInterrupted());
}
- interrupted() 메서드를 사용하면 앞에서 발생한 문제를 해결할 수 있다
결론
인터럽트를 활용하는 방법을 배웠다.
인터럽트는 WAITING, TIMED_WAITING 상태의 스레드를 RUNNABLE 상태로 전환시키고 싶을 때 사용하며 InterruptedException을 활용하여 구현한다.
또한 인터럽트의 상태를 직접 체크해서 사용해야 한다면 Thread.interrupted() 메서드를 이용하고 인터럽트의 상태를 확인하는 용도라면 Thread.currentThread().isInterrupted()를 사용한다.
인터럽트를 사용할 경우 반드시 인터럽트의 목적을 달성한 후에 false로 전환해야 문제가 발생(의도하지 않은 예외발생)하지 않는다.
'JAVA' 카테고리의 다른 글
[JAVA] 자바의 volatile 키워드와 메모리 가시성 (1) | 2024.09.23 |
---|---|
[JAVA] 스레드의 양보 Thread.yield() (0) | 2024.09.21 |
[JAVA] 스레드의 상태 (getState()) (3) | 2024.09.02 |
[JAVA] 자바에서 스레드를 만들고 사용하는 방법 (1) | 2024.08.30 |
[JAVA] JVM, 자바의 메모리 구조 (0) | 2024.08.30 |