여러 스레드가 같은 객체를 조작할 경우 코드가 번갈아 실행되기 때문에 의도치 않은 동작을 할 수가 있다. 한 스레드에서 값을 조작한 후 출력을 하려고 하는데 다른 스레드에서 다른 값으로 변경을 한다면 의도한 결과를 출력할 수가 없을 것이다.
하나의 스레드만 실행할 수 있는 메서드를 말한다. 해당 메서드가 실행되는 동안 다른 스레드는 해당 메서드가 실행이 끝날 때까지 대기해야 한다. 반환 타입 앞에 synchronized 키워드를 삽입하여 선언하면 된다.
public synchronized void method(){
// 임계 영역: 하나의 스레드만 실행
}
하나의 스레드만 실행되는 블록을 말한다. 블록 앞에 synchronized 키워드를 삽입하여 생성할 수 있다.
public void method(){
// 여러 스레드가 실행되는 영역
synchronized{
// 하나의 스레드만 실행되는 영역
}
// 여러 스레드가 실행되는 영역
}
상태 | 열거 상수 | 설명 |
---|---|---|
객체 생성 | NEW | 스레드 객체가 생성, 아직 start 메서드가 호출되지 않은 상태 |
실행 대기 | RUNNABLE | 실행 상태로 언제든지 갈 수 있는 상태 |
일시 정지 | BlOCKED | 사용하고자 하는 객체의 lock이 풀릴 때까지 기다리는 상태 ex) 다른 스레드에서 동기화 메서드나 블록 사용하는 경우 |
^ | WAITING | 다른 스레드가 통지할 때까지 기다리는 상태 ex) Object의 wait(), notify(), notifyAll() 메서드 |
^ | TIMED_WAITING | 주어진 시간 동안 기다리는 상태 ex) Thread의 sleep() 메서드 |
종료 | TERMINATED | 실행을 마친 상태 |
전체적인 상태 흐름을 나타내면 다음과 같다.
주의깊게 볼 점은 start 메서드가 호출되면 바로 실행되는 것이 아니라 실행 대기 상태에 있다가 스케줄링에 의해 실행과 실행 대기 상태를 왔다갔다 한다는 점이다.
다음과 같은 메서드들로 제어한다.
매개변수로 받은 시간 동안 스레드를 일시 정지하는 메서드이다.
try{
Thread.sleep(1000);
}catch(InterruptedException e){
// interrupt() 호출시 실행
}
sleep()를 호출하여 일시정지된 스레드에서 interrupt를 호출할 경우 InterruptException이 발생하여 catch문이 실행된다.
Thread.interrupted() 스레드에서 interrupted가 호출되었는지를 알려주는 메서드이기 때문에 이를 이용하면 된다. 혹은 인스턴스 메서드인 objThread.isinterrupted()를 이용할 수 있다. 이렇게 하면 sleep를 호출하지 않고도 interrupt 메서드의 기능을 이용할 수 있다.
다른 스레드에게 실행을 양보하는 메서드이다. 무의미한 반복을 하는 스레드일 경우 사용할 수 있다.
public void run(){
while(true){
if(work){
System.out.println("Thread A 작업 내용 : ");
}
else{
Thread.yield();
}
}
}
다른 스레드의 종료를 기다리는 메서드이다. 다음 그림에서 threadB.join()을 호출하면 ThreadA는 일시정지(Timed-Waiting) 상태가 되어 ThreadB의 종료를 기다렸다가 종료되었을 때 Runnable 상태가 된다.
public class SumThread extends Thread{
private long sum;
public long getSum() {
return sum;
}
public void setSum(long sum) {
this.sum = sum;
}
@Override
public void run() {
for(int i = 1;i < 10000; i++){
this.sum += 1;
}
}
}
public class JoinEx {
public static void main(String[] args) {
double avg = 0.0;
long total = 0;
SumThread sumThread = new SumThread();
sumThread.start();
try {
sumThread.join();
}catch (InterruptedException e){}
// sumThread 종료 이후 실행
total = sumThread.getSum();
avg = total / 10000.0;
System.out.println(total);
System.out.println(avg);
}
}
셋 다 Object의 메서드로, 동기화 메서드 또는 블록에서만 호출할 수 있는 메서드이다.
호출한 스레드는 일시정지(Blocked) 상태가 된다. 다른 스레드가 notify나 notifyAll을 호출해야 Runnable 상태가 된다. 주로 두 개의 스레드가 번갈아 가며 실행해야 할 경우 사용한다.
다른 스레드가 notify, notifyAll을 호출하기 전에도 시간이 지나면 자동으로 Runnable 상태가 된다.