자바 기본 튜 토리 얼 의 자바 스 레 드 대기 및 자바 깨 우기 스 레 드 자바 다 중 스 레 드 튜 토리 얼

이 장 에 서 는 스 레 드 대기/깨 우 는 방법 을 소개 합 니 다.관련 내용 은 1.wait(),notify(),notify All()등 방법 소개 2.wait()와 notify()3.wait(long timeout)와 notify()4.wait()와 notify All()5.왜 notify(),wait()등 함수 가 Thread 가 아 닌 Object 에 정의 되 어 있 습 니까?
wait(),notify(),notify All()등 방법 은 Object.자바 에서 wait(),notify(),notify All()등 인 터 페 이 스 를 정의 합 니 다.wait()의 역할 은 현재 스 레 드 를 대기 상태 에 들 어가 게 하 는 동시에 wait()도 현재 스 레 드 가 가지 고 있 는 자 물 쇠 를 방출 합 니 다.한편,notify()와 notify All()의 역할 은 현재 대상 의 대기 스 레 드 를 깨 우 는 것 입 니 다.notify()는 하나의 스 레 드 를 깨 우 는 것 이 고 notify All()은 모든 스 레 드 를 깨 우 는 것 입 니 다.
Object 클래스 에서 대기/깨 우기 API 에 대한 자세 한 정 보 는 다음 과 같 습 니 다:notify()        -- 이 대상 모니터 에서 기다 리 는 단일 스 레 드 를 깨 웁 니 다.notifyAll()   -- 이 대상 모니터 에서 기다 리 는 모든 스 레 드 를 깨 웁 니 다.wait()                                         -- 현재 스 레 드 를'대기(차단)상태'로 만 듭 니 다.'다른 스 레 드 가 이 대상 의 notify()방법 이나 notify All()방법 을 호출 할 때 까지'현재 스 레 드 가 깨 어 납 니 다('준비 상태'로 들 어 갑 니 다).wait(long timeout)                    -- 현재 스 레 드 를'대기(차단)상태'로 만 듭 니 다.'다른 스 레 드 가 이 대상 의 notify()방법 이나 notify All()방법 을 호출 하거나 지정 한 시간 을 초과 할 때 까지'현재 스 레 드 가 깨 어 납 니 다('준비 상태'로 들 어 갑 니 다).wait(long timeout, int nanos)  -- 현재 스 레 드 를'대기(차단)상태'로 합 니 다.'다른 스 레 드 가 이 대상 의 notify()방법 이나 notify All()방법 을 호출 하거나 다른 스 레 드 가 현재 스 레 드 를 중단 하거나 실제 시간 을 초과 할 때 까지'현재 스 레 드 가 깨 어 납 니 다('준비 상태'로 들 어 갑 니 다).
2.wait()와 notify()예제 아래 예제 를 통 해'wait()와 notify()가 함께 사용 하 는 상황'을 보 여 줍 니 다.

// WaitTest.java
class ThreadA extends Thread{

    public ThreadA(String name) {
        super(name);
    }

    public void run() {
        synchronized (this) {
            System.out.println(Thread.currentThread().getName()+" call notify()");
            // wait
            notify();
        }
    }
}

public class WaitTest {

    public static void main(String[] args) {

        ThreadA t1 = new ThreadA("t1");

        synchronized(t1) {
            try {
                // “ t1”
                System.out.println(Thread.currentThread().getName()+" start t1");
                t1.start();

                // t1 notify() 。
                System.out.println(Thread.currentThread().getName()+" wait()");
                t1.wait();

                System.out.println(Thread.currentThread().getName()+" continue");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

실행 결과:

main start t1
main wait()
t1 call notify()
main continue
결 과 는 다음 과 같다.다음 그림 은'메 인 스 레 드'와'스 레 드 t1'의 절 차 를 설명 한다.
(01)주의 하 세 요.그림 에서'메 인 스 레 드'는'메 인 스 레 드 main'을 대표 합 니 다.'스 레 드 t1"WaitTest 에서 시 작 된"스 레 드 t1"을 대표 합 니 다.'자물쇠'는't1 이라는 대상 의 동기 자물쇠'를 대표 합 니 다.(02)"메 인 스 레 드"는 new ThreadA("t1")를 통 해"스 레 드 t1"을 새로 만 듭 니 다.그 다음 에 synchronized(t1)를 통 해't1 대상 의 동기 화 자물쇠'를 가 져 옵 니 다.그리고 t1.start()를 호출 하여'스 레 드 t1'을 시작 합 니 다.(03)"메 인 스 레 드"는 t1.wait()를 실행 하여"t1 대상 의 잠 금"을 풀 고"대기(차단)상태"에 들 어 갑 니 다.t1 대상 의 스 레 드 가 notify()나 notify All()을 통 해 깨 어 날 때 까지 기 다 립 니 다.(04)"스 레 드 t1"이 실 행 된 후 synchronized(this)를 통 해"현재 대상 의 자물쇠"를 가 져 옵 니 다.이 어 notify()를 호출 하여'현재 대상 의 대기 스 레 드',즉'메 인 스 레 드'를 깨 웁 니 다.(05)"스 레 드 t1"이 실 행 된 후"현재 대상 의 자물쇠"를 방출 합 니 다.이 어'메 인 스 레 드'는't1 대상 의 자물쇠'를 가 져 온 다음 에 실 행 됩 니 다.
위의 코드 에 대해 서?한 친구 가 물 었 습 니 다.t1.wait()는'스 레 드 t1'을 기다 리 게 해 야 합 니 다.그런데 왜'메 인 스 레 드 main'을 기다 리 게 했 을 까?이 문 제 를 풀기 전에 jdk 문서 에서 wait 에 대한 소 개 를 살 펴 보 겠 습 니 다.

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
In other words, this method behaves exactly as if it simply performs the call wait(0).
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
중국어
다른 스 레 드 가 notify()나 notify All()을 호출 하여 이 스 레 드 를 깨 울 때 까지'현재 스 레 드'를 기다 리 게 합 니 다.다시 말 하면 이 방법 은 wait(0)의 효과 와 같다!덧 붙 여 wait(long millis)방법 에 대해 서 는 millis 가 0 일 때 notify()나 notifyAll()에 의 해 깨 어 날 때 까지 무한 기다 림 을 표시 합 니 다."현재 스 레 드 는 wait()를 호출 할 때 이 대상 의 동기 화 잠 금 을 가 져 야 합 니 다.이 스 레 드 는 wait()를 호출 한 후 이 자 물 쇠 를 방출 합 니 다.그리고'다른 스 레 드'가 대상 의 동기 화 잠 금 을 호출 할 때 까지 기다 리 는 notify()나 notify All()방법 입 니 다.그리고 이 스 레 드 는'이 대상 의 동기 화 자물쇠'를 다시 가 져 올 때 까지 기 다 렸 다가 계속 실 행 될 수 있 습 니 다.메모:jdk 의 설명 에서 wait()의 역할 은'현재 스 레 드'를 기다 리 게 하 는 것 이 고,'현재 스 레 드'는 cpu 에서 실행 중인 스 레 드 를 말 합 니 다!t1.wait()는'스 레 드 t1'을 통 해 호출 되 는 wait()방법 이지 만 t1.wait()를 호출 하 는 곳 은'메 인 스 레 드 main'에 있다 는 뜻 이다.주 스 레 드 는'현재 스 레 드',즉 실행 상태 여야 t1.wait()를 실행 할 수 있 습 니 다.그래서 이때 의'현재 스 레 드'는'메 인 스 레 드 main'입 니 다!따라서 t1.wait()는'주 스 레 드'를 기다 리 게 하 는 것 이지'스 레 드 t1'이 아 닙 니 다!
3.wait(long timeout)와 notify()wait(long timeout)는 현재 스 레 드 를'대기(차단)상태'로 만 듭 니 다.'다른 스 레 드 가 이 대상 의 notify()방법 이나 notify All()방법 을 호출 하거나 지정 한 시간 을 초과 할 때 까지'현재 스 레 드 가 깨 어 납 니 다('준비 상태'로 들 어 갑 니 다).다음 예 는 wait(long timeout)가 시간 을 초과 한 상태 에서 스 레 드 가 깨 어 난 상황 을 보 여 주 는 것 입 니 다.

// WaitTimeoutTest.java
class ThreadA extends Thread{

    public ThreadA(String name) {
        super(name);
    }

    public void run() {
        System.out.println(Thread.currentThread().getName() + " run ");
        // , 。
        while(true)

    }
}

public class WaitTimeoutTest {

    public static void main(String[] args) {

        ThreadA t1 = new ThreadA("t1");

        synchronized(t1) {
            try {
                // “ t1”
                System.out.println(Thread.currentThread().getName() + " start t1");
                t1.start();

                // t1 notify() notifyAll() , 3000ms ; 。
                System.out.println(Thread.currentThread().getName() + " call wait ");
                t1.wait(3000);

                System.out.println(Thread.currentThread().getName() + " continue");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

실행 결과:

main start t1
main call wait
t1 run                  // 3 ... “main continue”
main continue
결과 설명:다음 그림 은'메 인 스 레 드'와'스 레 드 t1'의 절 차 를 설명 한다.(01)주의 하 세 요.그림 에서'메 인 스 레 드'는 WaitTimeoutTest 메 인 스 레 드(즉,스 레 드 main)를 대표 합 니 다."스 레 드 t1 은 WaitTest 에서 시 작 된 스 레 드 t1 을 대표 합 니 다.'자물쇠'는't1 이라는 대상 의 동기 자물쇠'를 대표 합 니 다.(02)메 인 스 레 드 main 에서 t1.start()를 실행 하여"스 레 드 t1"을 시작 합 니 다.(03)메 인 스 레 드 main 은 t1.wait(3000)를 실행 합 니 다.이때 메 인 스 레 드 는'차단 상태'에 들 어 갑 니 다."t1 대상 잠 금 에 사용 할 스 레 드 는 notify()또는 notify All()을 통 해 깨 워 야 합 니 다"또는"3000 ms 초과 후"주 스 레 드 main 이"준비 상태"에 들 어가 야 실행 할 수 있 습 니 다.(04)"스 레 드 t1"이 실 행 된 후 순환 에 들 어가 계속 실 행 됩 니 다.(05)3000 ms 를 초과 하면 메 인 스 레 드 main 은'준비 상태'에 들 어간 다음 에'운행 상태'에 들어간다.
4.wait()와 notify All()은 앞의 예 시 를 통 해 notify()가 이 대상 모니터 에서 기다 리 는 단일 스 레 드 를 깨 울 수 있다 는 것 을 알 고 있 습 니 다.다음은 notify All()의 용법 을 예시 로 보 여 줍 니 다.이 대상 모니터 에서 기다 리 는 모든 스 레 드 를 깨 우 는 역할 을 합 니 다.

public class NotifyAllTest {

    private static Object obj = new Object();
    public static void main(String[] args) {

        ThreadA t1 = new ThreadA("t1");
        ThreadA t2 = new ThreadA("t2");
        ThreadA t3 = new ThreadA("t3");
        t1.start();
        t2.start();
        t3.start();

        try {
            System.out.println(Thread.currentThread().getName()+" sleep(3000)");
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized(obj) {
            // 。
            System.out.println(Thread.currentThread().getName()+" notifyAll()");
            obj.notifyAll();
        }
    }

    static class ThreadA extends Thread{

        public ThreadA(String name){
            super(name);
        }

        public void run() {
            synchronized (obj) {
                try {
                    //
                    System.out.println(Thread.currentThread().getName() + " wait");

                    // wait
                    obj.wait();

                    //
                    System.out.println(Thread.currentThread().getName() + " continue");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

실행 결과:

t1 wait
main sleep(3000)
t3 wait
t2 wait
main notifyAll()
t2 continue
t3 continue
t1 continue
결과 설명:아래 의 흐름 도 를 참고 하 세 요.(01)메 인 스 레 드 에 3 개의 스 레 드"t1","t2","t3"를 새로 만 들 고 시작 합 니 다.(02)메 인 스 레 드 는 sleep(3000)을 통 해 3 초 간 휴면 한다.메 인 스 레 드 가 3 초 동안 휴면 하 는 과정 에서 우 리 는't1','t2'와't3'라 는 세 개의 스 레 드 가 모두 실행 되 었 다 고 가정 합 니 다."t1"을 예 로 들 면,실행 할 때,다른 라인 이 notify()나 액 nofityAll()을 통 해 깨 어 날 때 까지 obj.wait()를 실행 합 니 다.같은 이치 로"t2"와"t3"도 다른 스 레 드 가 nofity()나 nofity All()을 통 해 깨 어 나 기 를 기다 리 고 있 습 니 다.(03)메 인 스 레 드 는 3 초 간 휴면 한 후 계속 운행 한다.obj.notifyAll()을 실행 하여 obj 의 대기 스 레 드 를 깨 웁 니 다.즉,"t1","t2","t3"세 스 레 드 를 깨 웁 니 다.이 어 메 인 스 레 드 의 synchronized(obj)가 실 행 된 후 메 인 스 레 드 는"obj 자물쇠"를 방출 합 니 다.이렇게 하면't1','t2'와't3'는'obj 자물쇠'를 가 져 와 계속 실 행 됩 니 다!5.왜 notify(),wait()등 함수 가 Thread 에 있 는 Object 의 wait(),notify()등 함수 가 아 닌 Object 에 정의 되 어 있 는 지,synchronized 와 마찬가지 로'대상 의 동기 화 잠 금'을 작 동 합 니 다.
wait()는'현재 스 레 드'를 기다 리 게 합 니 다.스 레 드 가 대기 상태 에 들 어가 기 때문에 스 레 드 는 잠 금 이 가지 고 있 는'동기 잠 금'을 풀 어야 합 니 다.그렇지 않 으 면 다른 스 레 드 가 이'동기 잠 금'을 가 져 오지 못 해 실행 할 수 없습니다!OK.스 레 드 가 wait()를 호출 하면 자물쇠 가 가지 고 있 는'동기 화 자물쇠'를 방출 합 니 다.그리고 앞의 소개 에 따 르 면,우 리 는 대기 라인 이 notify()또는 notify All()에 의 해 깨 어 날 수 있다 는 것 을 알 고 있다.지금,notify()는 무엇 에 근거 하여 대기 라인 을 깨 우 는 것 입 니까?아니면 wait()대기 스 레 드 와 notify()는 무엇 을 통 해 연결 되 어 있 습 니까?정 답 은'대상 의 동기 화 자물쇠'에 따른다.
대기 스 레 드 를 깨 우 는 그 스 레 드(우 리 는'스 레 드 깨 우기'라 고 합 니 다)는'이 대상 의 동기 화 잠 금'(이 동기 화 잠 금 은 대기 스 레 드 의 동기 화 잠 금 과 동일 해 야 합 니 다)을 가 져 오고 notify()나 notify All()방법 을 호출 한 후에 야 대기 스 레 드 를 깨 울 수 있 습 니 다.스 레 드 가 깨 어 날 때 까지 기다 리 지만;그러나 스 레 드 를 깨 우 는 데'이 대상 의 동기 화 자물쇠'가 있 기 때문에 즉시 실행 할 수 없습니다.스 레 드 를 깨 워'대상 의 동기 화 잠 금'을 풀 어 준 후에 스 레 드 를 기 다 려 야'대상 의 동기 화 잠 금'을 얻 고 계속 실행 할 수 있 습 니 다.
한 마디 로 하면 notify(),wait()는'동기 자물쇠'에 의존 하고'동기 자물쇠'는 대상 자물쇠 가 가지 고 있 으 며 대상 마다 하나 밖 에 없습니다!이것 이 바로 notify(),wait()등 함수 가 Thread 클래스 가 아 닌 Object 클래스 에 정 의 된 이유 입 니 다.

좋은 웹페이지 즐겨찾기