본문 바로가기

자바

[스레드] 7. 스레드 상태제어

예제1: 생산자스레드가 데이터를 만들면, 소비자스레드가 읽는다.

package ex05_wait_notify;

public class WaitNotifyExample {
    public static void main(String[] args) {
        DataBox dataBox = new DataBox();

        ProducerThread producerThread = new ProducerThread(dataBox);
        ConsumerThread consumerThread = new ConsumerThread(dataBox);
        
        producerThread.start();
        consumerThread.start();
    }
}

실행결과:

ProducerThread가 생성한 데이터: Data-1
ConsumerThread가 읽은 데이터 : Data-1
ProducerThread가 생성한 데이터: Data-2
ConsumerThread가 읽은 데이터 : Data-2
ProducerThread가 생성한 데이터: Data-3
ConsumerThread가 읽은 데이터 : Data-3

package ex05_wait_notify;

public class DataBox {
    private String data;

    public synchronized String getData() {
        if (this.data == null) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }

        String returnValue = data;
        System.out.println("ConsumerThread가 읽은 데이터 : " + returnValue);
        data = null;
        notify();

        return data;
    }

    public synchronized void setData(String data) {
        if (this.data != null) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
        this.data = data;
        System.out.println("ProducerThread가 생성한 데이터: " + data);
        notify();
    }
}
package ex05_wait_notify;

public class ProducerThread extends Thread {
    private DataBox dataBox;

    public ProducerThread(DataBox dataBox) {
        this.setName("ProducerThread");
        this.dataBox = dataBox;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 3; i++) {
            String data = "Data-" + i;
            dataBox.setData(data);
        }
    }
}
package ex05_wait_notify;

public class ConsumerThread extends Thread {
    private DataBox dataBox;

    public ConsumerThread(DataBox dataBox) {
        this.setName("ConsumerThread");
        this.dataBox = dataBox;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 3; i++) {
            String data = dataBox.getData();
        }
    }
}

 

※ 스레드의 안전한 종료 - stop 플래그, interrupt()

- 경우에 따라서는 실행 중인 스레드를 즉시 종료할 필요가 있다.

- stop() 메소드

스레드 즉시 종료

스레드를 갑자기 종료하게되면 사용 중이던 자원들이 불안전한 상태로 남겨진다.

deprecated

- stop 플래그를 이용하는 방법

stop 플래그로 메소드의 정상 종료를 유도한다.

package ex06_stop;

public class StopFlagExample {
    public static void main(String[] args) {
        PrintThread1 printThread = new PrintThread1();

        printThread.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }

        printThread.setStop(true);
    }
}

실행결과:

...

실행 중
실행 중
실행 중
실행 중
실행 중
실행 중
자원 정리
실행 종료

package ex06_stop;

public class PrintThread1 extends Thread {
    private boolean stop;

    public void setStop(boolean stop) {
        this.stop = stop;
    }

    @Override
    public void run() {
        while (!stop) {
            System.out.println("실행 중");
        }
        System.out.println("자원 정리");
        System.out.println("실행 종료");
    }
}

 

 

- interrupt() 메소드를 이용하는 방법

일시정지 상태일 경우 InterruptedException 발생

실행대기 또는 실행상태에서는 InterruptedException 발생x

일시정지 상태로만들지 않고 while문을 빠져나오는 방법

boolean status = Thread.interrupt();
boolean status = objThread.isInterrupted();

1초 스레드 종료 예제

package ex06_stop;

public class InterruptExample {
    public static void main(String[] args) {
        PrintThread2 printThread2 = new PrintThread2();
        printThread2.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }

        printThread2.interrupt();
    }
}
package ex06_stop;

public class PrintThread2 extends Thread {
    @Override
    public void run() {
        try{
            while (true) {
                System.out.println("실행 중");
                Thread.sleep(1);
            }
        }catch (InterruptedException e){}

        System.out.println("자원정리");
        System.out.println("실행 종료");
    }
}

리팩토링 버전:

package ex06_stop;

public class PrintThread2 extends Thread {
    @Override
    public void run() {
//        try{
//            while (true) {
//                System.out.println("실행 중");
//                Thread.sleep(1);
//            }
//        }catch (InterruptedException e){}

        while (true) {
            System.out.println("실행 중");
            if (Thread.interrupted()) {
                break;
            }
        }
        
        System.out.println("자원정리");
        System.out.println("실행 종료");
    }
}