스레드 - (2)
4절 동기화 메소드와 동기화 블록
공유 객체를 사용할 때의 주의할 점
- 멀티 스레드가 하나의 객체를 공유해서 생기는 오류
동기화 메소드 및 동기화 블록 - synchronized
단 하나의 스레드만 실행할 수 있는 메소드 또는 블록을 말한다.
다른 스레드는 메소드나 블록이 실행이 끝날 때까지 대기해야한다.
동기화 메소드
public synchronized void method() {
임계 영역; //단 하나의 스레드만 실행
}
- 동기화 블록
public void method() {
//여러 스레드가 실행 가능 영역
synchronized(공유 객체) {
임계영역 //단 하나의 스레드만 실행
}
//여러 스레드가 실행 가능 영역
}
5. 스레드 상태
🍤 스레드 상태
상태 | 열거 상수 | 설명 |
---|---|---|
객체 생성 | NEW | 스레드 객체가 생성, 아직 start() 메소드가 호출되지 않은 상태 |
실행 대기 | RUNNABLE | 실행 상태로 언제든지 갈 수 있는 상태 |
일시 정지 | BLOCKED | 사용하는 객체의 락이 풀릴 때까지 기다리는 상태 |
WAITING | 다른 스레드가 통지할 때가지 기다리는 상태 | |
TIMED_WAITING | 주어진 시간 동안 기다리는 상태 | |
종료 | TERMINATED | 실행을 마친상태 |
6. 스레드 상태 제어
🍤 상태 제어
- 실행 중인 스레드의 상태를 변경하는 것을 말한다.
- 상태 변화를 가져오는 메소드의 종류
주어진 시간동안 일시정지 - sleep()
try { Thread.sleep(1000); } catch(InterruptedException e) { //interrupt() 메소드가 호출되면 실행 }
- 얼마동안 일시 정지 상태로 있을 것인지, 밀리세컨드(1/1000)단위로 지정
- 일시 정지 상태에서 interrupt() 메소드가 호출되면 InterruptedException 발생
다른 스레드에게 실행 양보 - yield()
다른 스레드의 종료를 기다림 - join()
- 계산 작업을하는 스레드가 모든 계산 작업을 마쳤을 때, 계산 결과값을 받아 이용하는 경유에 주로 사용
스레드간 협업 - wait(), notify(), notifyAll()
동기화 메소드 또는 블록에서만 호출 가능한 Object의 메소드
wait()
- 호출한 스레드는 일시 정지가 된다.
- 다른 스레드가 notify() 또는 notifyAll()을 호출하면 실행 대기 상태가 된다.
wait(long timeout) / wait(long timeout, int nanos)
- notify()가 호출되지 않아도 시간이 지나면 스레드가 자동적으로 실행 대기 상태가 된다.
두개의 스레드가 교대로 번갈아 가며 실행해야할 경우 주로 사용
스레드의 안전한 종료(stop 플래그, interrupt())
Thread는 스레드를 즉시 종료시키기 위해서 stop()메소드를 제공 - > deprecated 되었다.
why? stop() 메소드를 사용할 시 스레드가 사용 중이던 자원들이 불안전한 상태로 남겨진다.
stop 플래그를 이용하는 방법
public class PrintThread1 extends Thread { private boolean stop; //stop 플래그 필드 public void setstop(boolean stop) { this.stop = stop; } public void run() { while(!stop) { //스레드가 반복 실행하는 코드; System.out.println("실행 중"); } // 스레드가 사용한 자원 정리 System.out.println("자원 정리"); System.out.println("실행 종료"); } }
interrupt() 메소드를 이용하는 방법
:small_blue_diamond: 스레드가 일시정지 상태에 있을 때 InterruptedException예외를 발생시키는 역할
즉 실행대기 또는 실행 상태에 있을 때 interrupt() 메소드가 실행되면 즉시 예외가 발생되지 않고, 미래에 일시 정지 상태가 되면 예외가 발생한다는 뜻!
:small_blue_diamond: 일시정지를 만들지 않고도 interrupt() 호출 여부를 알 수 있다.
interrupt()메소드가 호출되었다면 true를 리턴한다!
```java
//정적메소드로 현재 스레드가 interrupted되었는지 확인하는 것
boolean status = Thread.interrupted();
boolean status = objThread.isInterrupted(); //인스턴스 메소드
```
```java
public class PrintThread2 extends Thread {
public void run(){
while(true){
System.out.println("실행중");
if(Thread.interrupted()){
break; //while문을 빠져나옴
}
}
System.out.println("자원 정리");
System.out.println("실행 종료");
}
}
```
7절 데몬 스레드
주 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드
주 스레드가 종료되면 데몬 스레드는 강제적으로 자동 종료
ex) 워드프로세서의 자동저장, 미디어플레이어의 동영상 및 음악 재생, 가비지 컬렉터
데몬 스레드 설정
주 스레드가 데몬이 될 스레드의 setDaemon(true)를 호출
반드시 start() 메소드 호출전에 setDaemon(true)를 호출해야한다.
-> illegalThreadStateException이 발생
public static void main(String[] args) { AutoSaveThread thread = new AutoSaveThread(); thread.setDaemon(true); threaed.start(); }
- 데몬 스레드 확인 방법
- isDaemon() 메소드의 리턴값을 조사 데몬 스레드일 경우 true를 리턴한다.
8절 스레드 그룹
관련된 스레드를 묶어서 관리할 목적으로 이용한다.
스레드 그룹은 계층적으로 하위 스레드 그룹을 가질 수 있다.
- 자동 생성되는 스레드 그룹
- system 그룹 : JVM 운영에 필요한 스레드를 포함
- System/main 그룹 : 메인 스레드를 포함
- 스레드는 반드시 하나의 스레드 그룹에 포함
- 기본적으로 자신을 생성한 스레드와 같은 스레드 그룹에 속하게 된다.
- 명시적으로 스레드 그룹에 포함시키지 않으면 기본적으로 system/main 그룹에 속한다.
스레드 그룹 이름 얻기
ThreadGroup Group = Thread.currentThread().getThreadGroup(); String groupName = Group.getName();
스레드 그룹 생성
ThreadGroup tg = new ThreadGroup(String name); ThreadGroup tg = new ThreaedGroup(ThreadGroup parent, String name);
- 부모(parent) 그룹을 지정하지 않으면 현재 스레드가 속한 그룹의 하위 그룹으로 생성
- 스레드를 그룹에 명시적으로 포함시키는 방법
- 스레드 그룹의 일괄 interrupt()
- 스레드 그룹의 interrupt()를 호출하면 소속된 모든 스레드의 interrupt()가 호출된다.
스레드 그룹의 list()메소드 출력 내용
ThreadGroup mainGroup = Thread.currentThread.getThreadGroup(); mainGroup.list();