자바 에서 thread 의 join 방법 은 왜 스 레 드 를 새치기 할 수 있 습 니까?

2808 단어 자바
면접 에서 이런 문제 가 자주 발생 합 니 다. 메 인 스 레 드 에 두 개의 스 레 드 가 있 는데 두 개의 스 레 드 가 순서대로 실 행 될 수 있다 면?답 은 당연히 join 으로 두 스 레 드 순 서 를 실행 시 키 는 것 이다. 먼저 구체 적 인 코드 를 살 펴 보 자.
public class ThreadOfJoin {

    public static void main(String[] args) throws Exception {
        MyThread luck = new MyThread("Luck");
        MyThread timi = new MyThread("Timi");

        luck.start();
        luck.join();
        timi.start();
    }

    @Data
    static class MyThread extends Thread {
        private String userName;
        public MyThread(String userName) {
            this.userName = userName;
        }

        @Override
        public void run() {
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.println(userName + " - " + i);
                    Thread.sleep(1000);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

각 스 레 드 가 시 작 된 후 다섯 번 의 정 보 를 인쇄 하고 서로 다른 이름 으로 어느 스 레 드 가 인쇄 되 었 는 지 구분 합 니 다.실행 결 과 는 다음 과 같다.
Luck - 0
Luck - 1
Luck - 2
Luck - 3
Luck - 4
Timi - 0
Timi - 1
Timi - 2
Timi - 3
Timi - 4

결 과 를 통 해 join 은 두 스 레 드 를 순서대로 실행 할 수 있 습 니 다. 그런데 왜 join 은 스 레 드 순 서 를 제어 할 수 있 습 니까? join 의 구체 적 인 실현 을 살 펴 보 겠 습 니 다.
//外部调用的方法
public final void join() throws InterruptedException {
    join(0);
}
//内部的具体实现
public final synchronized void join(long millis) throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;

    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (millis == 0) {
        while (isAlive()) {
            wait(0);
        }
    } else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

먼저 join 은 synchronized 키 워드 를 통 해 스 레 드 의 안전 을 확보 합 니 다. 메 인 스 레 드 는 luck. start () 를 호출 한 후에 luck. join () 을 호출 했 습 니 다. luck 스 레 드 가 실행 되 지 않 으 면 메 인 스 레 드 는 다음 코드 에 의 해 막 힐 것 입 니 다.
if (millis == 0) {//join()方法默认milis为0
    while (isAlive()) {//线程未执行完成,此条件为true
        wait(0);//等待notify
    }
}

luck 스 레 드 가 실 행 된 후에 이 스 레 드 의 생명 주기 가 곧 끝 날 것 입 니 다. 생명 주기 가 끝나 기 전에 luck 스 레 드 는 notify All () 방법 을 사용 하여 이 대상 의 자 물 쇠 를 기다 리 고 있 는 모든 스 레 드 (나 는 곧 죽 을 것 이 니 더 이상 기다 리 지 마 세 요) 를 알려 줍 니 다.wait (0) 는 notify 를 받 은 후 다시 isAlive () 판단 을 합 니 다. luck 이 사망 한 후 순환 을 뛰 어 내 립 니 다. join 방법 이 끝 난 후에 메 인 스 레 드 의 다른 코드 를 계속 실행 합 니 다.
또한 join 방법 에서 시간 파 라 메 터 를 전달 할 수 있 는 것 도 볼 수 있 습 니 다. 아마도 역할 은 지 정 된 시간 을 기다 린 후에 이전 스 레 드 가 완성 되 지 않 았 다 면 오래 기다 리 지 않 는 것 입 니 다.

좋은 웹페이지 즐겨찾기