자바 의 join 방법 원리 에 대한 상세 한 설명

8053 단어 자바 병발
1.synchronized 의 대상 자 물 쇠 는 스 레 드 의 인 스 턴 스 입 니 다.
우 리 는 동기 화 된 코드 를 패키지 로 묶 을 수 있 습 니 다.
Object obj = new Object();
synchronized(obj){
   obj.wait();    //       
}

이 때 스 레 드 는 obj.wait()에서 기 다 립 니 다.계속 실행 하려 면 다른 스 레 드 가 notify,notify All 을 통 해 깨 우거 나 중단 되 어야 합 니 다.그런데 만약 에 obj 가 하나의 라인 실례 라면 어떻게 될까요?
아래 의 예 와 같이:
public class HighConcurrency {

	public static void main(String[] args) {
		try {
			Thread threadTest = new Thread(){
				public void run(){
					System.out.println("       ");
					try {
						Thread.sleep(2000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
			threadTest.start();
			synchronized(threadTest){
			    threadTest.wait();		//        ,        notifyAll()  
			}
			System.out.println("      ");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

출력:
       
      

먼저 스 레 드 threadTest 를 시작 합 니 다.메 인 스 레 드 가 threadTest.wait()로 실 행 될 때 메 인 스 레 드 가 기다 리 고 있 습 니 다.이상 하 게 도 메 인 스 레 드 는 다른 스 레 드 가 notify 나 notify All 방법 으로 깨 우지 않 았 습 니 다.뒤에 있 는 문 구 를 직접 실 행 했 습 니 다.synchronized 가 대상 자 물 쇠 를 스 레 드 의 인 스 턴 스 로 얻 었 을 때 이 스 레 드 가 종 료 될 때 스 레 드 자체 의 notify All()방법 을 호출 하여 이 스 레 드 대상 에 기다 리 는 모든 스 레 드 를 알려 줍 니 다.
이게 무슨 애플 리 케 이 션 이 죠?
다음 과 같이 저 는 키 스 레 드 를 열 어 데 이 터 를 계산 하고 싶 습 니 다.저 는 계산 한 후에 최종 결 과 를 계산 한 후에 메 인 스 레 드 에서 한 마디 더 출력 하고 싶 습 니 다(계산 결과 에 대한 피드백 이 라 고 생각 합 니 다).이때 상기 와 유사 한 코드 를 사용 할 수 있 습 니 다.
class MyThread extends Thread {
	@Override
	public void run() {
		try {
			int secondValue = (int) (Math.random() * 3000);
			System.out.println(secondValue);
			Thread.sleep(secondValue);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
public class HighConcurrency {

	public static void main(String[] args) {
		try {
			MyThread threadTest = new MyThread();
			threadTest.start();
			synchronized(threadTest){
				threadTest.wait();	//        ,        notifyAll()  
			}
			System.out.println("   threadTest           ,    ");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

출력:
1135
   threadTest           ,    

과정 은 설명 이 많 지 않 습 니 다.바로 스 레 드 인 스 턴 스 를 이용 하여 대상 자 물 쇠 를 만 들 때 스 레 드 가 실 행 된 후에 스 레 드 자체 의 notify All()방법 을 호출 합 니 다.이때 메 인 스 레 드 는 계속 실 행 됩 니 다.사용 처 는 스 레 드 의 실행 순 서 를 제어 할 수 있 습 니 다.예 를 들 어 저 는 스 레 드 를 계산 하 게 할 수 있 습 니 다.서브 스 레 드 가 계산 한 후에 메 인 스 레 드 에서 계산 결 과
2.Join 의 원리
자바 의 join 방법 도 스 레 드 의 실행 순 서 를 제어 할 수 있 고 위의 코드 기능 은 join 방법 을 사용 하면 편리 하 게 실현 할 수 있 습 니 다.
class MyThread extends Thread {
	@Override
	public void run() {
		try {
			int secondValue = (int) (Math.random() * 3000);
			System.out.println(secondValue);
			Thread.sleep(secondValue);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
public class HighConcurrency {

	public static void main(String[] args) {
		try {
			MyThread threadTest = new MyThread();
			threadTest.start();
			threadTest.join();
			System.out.println("   threadTest           ,    ");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

출력 할 때 기능 이 같 습 니 다.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) {             //      join(0)
            while (isAlive()) {        //         ,         
                wait(0);               
            }
        } else {                       //      join(time)
            while (isAlive()) {               //         
                long delay = millis - now;    
                if (delay <= 0) {
                    break;
                }
                wait(delay);                 //  delay           
                now = System.currentTimeMillis() - base;
            }
        }
 }

그 중 핵심 코드 는 다음 과 같다.
while (isAlive()) {        //  join          
      wait(0);             //    
 }

isAlive()방법 은 아래 에 상세 하 게 소개 할 것 입 니 다.wait(0),wait(0)가 무슨 뜻 인지 먼저 보 겠 습 니 다.아래 wait()방법 소스 코드 를 보 세 요.사실 wait()방법 은 wait(0)방법 으로 이 루어 진 것 입 니 다.wait(0)는 계속 기다 리 게 하 는 것 입 니 다.여기 서 알 수 있 듯 이 join 방법 은 본질 적 으로 위의 스 레 드 인 스 턴 스 를 대상 으로 잠 그 는 원리 입 니 다.스 레 드 가 종 료 될 때 스 레 드 자체 의 notify All()방법 을 호출 하여 이 스 레 드 대상 에 기다 리 는 모든 스 레 드 의 특징 을 알 립 니 다.
public final void wait() throws InterruptedException {
    wait(0);
}

3.while(isAlive)문장의 역할 을 설명 한다.
다음 간단 한 코드 가 있 습 니 다:
코드 구현:
public class HighConcurrency {
	 
    // 1.   T2、T3    ,     T2 T1      ,T3 T2      
        final Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //   t1  ,  t1     
                    t1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2");
            }
        });
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //   t2  ,  t2     
                    t2.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t3");
            }
        });
        t3.start();//               ,      !
        t2.start();
    }
}

프로그램 출력:
t2
t3

먼저 t3.start()를 실 행 했 고 t3 스 레 드 의 run 방법 에서 t2.join()을 실 행 했 습 니 다.이때 두 가지 상황 이 있 습 니 다.t2.start()를 실행 하지 않 았 을 수도 있 고 t2.start()를 실 행 했 을 수도 있 습 니 다.t2 는 실 행 될 때 상태 이기 때문에 여기 서 알 수 있 습 니 다.join 소스 코드 중 while(isAlive().사실 while(this.isAlive()에 해당 하 는 것 은 이곳 의 t2 가 이미 실행 상태 인지 아 닌 지 를 판단 하 는 것 과 같다.이렇게 디자인 된 것 은 t2 스 레 드 가 실행 되 지 않 는 것 을 방지 하기 위해 서 입 니 다.이때 t3 스 레 드 가 wait(0)방법 을 직접 실행 하면 코드 가 끊 겨 죽 을 것 입 니 다.
인증 을 위해 코드 를 다음 으로 변경 합 니 다.
        t3.start();
        try {
		Thread.sleep(10);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
        t2.start();

현재 출력:
t3
t2

분석:t2.start()와 t3.start()사이 의 시간 간격 을 길 게 합 니 다.이렇게 하면 t3 스 레 드 에서 t2.join()을 실행 하지 않 을 때 t2 시 초기 상태 가 실행 상태 가 아니 라 는 것 을 보증 합 니 다.이때 while(isAlive()가 성립 되 지 않 고 wait(0)방법 을 실행 하지 않 기 때문에 t3 스 레 드 는 기다 리 지 않 고 t3 를 먼저 출력 합 니 다.
그리고 코드 를 다음 과 같이 변경 합 니 다.t2.join()을 실행 할 때 t2.start()가 실행 되 었 고 t2 가 실행 상태 에 있 음 을 보증 합 니 다.
public class HighConcurrency {
	
    public static void main(String[] args) {
 
        final Thread t2 = new Thread(new Runnable() {
 
            @Override
            public void run() {         
                System.out.println("t2");
            }
        });
        Thread t3 = new Thread(new Runnable() {
 
            @Override
            public void run() {
                try {
                	Thread.sleep(10);    //    t2         
                    t2.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t3");
            }
        });
        t3.start();
        t2.start();
    }
}

현재 출력:
t2
t3

분석:t3 스 레 드 에서 t2.join()방법 을 실행 하기 전에 sleep(10)방법 을 먼저 실 행 했 습 니 다.t2.join()을 실행 할 때 t2 는 이미 실 행 된 상태 이기 때문에 이때 t3 는 wait(0)방법 을 실행 하고 t2 가 먼저 실 행 될 때 까지 기 다 립 니 다.t3 는 계속 실 행 됩 니 다.그래서 t2 t3 를 출력 합 니 다.
 
참고:
http://uule.iteye.com/blog/1101994
https://www.nowcoder.com/questionTerminal/d8a288fc416c4d638dfb042e1be239fc?from=14pdf
http://www.cnblogs.com/paddix/p/5381958.html

좋은 웹페이지 즐겨찾기