자바 의 join 방법 원리 에 대한 상세 한 설명
8053 단어 자바 병발
우 리 는 동기 화 된 코드 를 패키지 로 묶 을 수 있 습 니 다.
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