이 스레드 조인 코드는 무엇을 의미합니까?


156

이 코드에서 두 조인과 중단은 무엇을 의미합니까? t1.join()원인이 t2될 때까지 중지 t1종료?

Thread t1 = new Thread(new EventThread("e1"));
t1.start();
Thread t2 = new Thread(new EventThread("e2"));
t2.start();
while (true) {
   try {
      t1.join();
      t2.join();
      break;
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
}


3
스레드 종료를 차단하고 기다릴 때 왜 while 루프를 사용 했습니까?
Mehdi

@MahdiElMasaoudi 스레드가 중단 된 경우에도 계속 대기하려면? 아마 그렇게하는 좋은 방법은 아닙니다
forresthopkinsa

도움이 되었으면 여기에 답변을 수락하십시오.
Gray

언급했듯이 메소드 while(true)를 호출 할 필요가 없습니다 join.
Chaklader Asfak Arefe

답변:


311

이 스레드 조인 코드는 무엇을 의미합니까?

Thread.join()javadocs 메소드 에서 인용하려면 다음을 수행하십시오 .

join() 이 스레드가 죽을 때까지 기다립니다.

예제 코드를 실행하는 스레드가있을 수 있습니다. 아마도 주요 스레드 일 것입니다 .

  1. 기본 스레드는 t1t2스레드를 작성하고 시작합니다 . 두 개의 스레드가 병렬로 실행되기 시작합니다.
  2. 메인 스레드 t1.join()t1스레드가 완료 될 때까지 대기하도록 호출 합니다 .
  3. t1스레드 완료하고 t1.join()주 스레드의 방법으로 돌아갑니다. 전화를 걸기 t1전에 이미 완료 되었을 수 있습니다 join().이 경우 join()전화가 즉시 돌아옵니다.
  4. 메인 스레드 t2.join()t2스레드가 완료 될 때까지 대기하도록 호출 합니다 .
  5. t2스레드 완료 (또는 그이 전에 완료 수도 t1스레드가했던)와 t2.join()메인 스레드의 방법으로 돌아갑니다.

t1t2스레드가 병렬 로 실행 되고 있지만이를 시작한 기본 스레드가 완료되기를 기다려야 계속 진행할 수 있음을 이해해야합니다 . 그것은 일반적인 패턴입니다. 또한,t1 및 / 또는 t2완료 할 수 전에 메인 스레드 호출 join()그들에. 그렇다면 join()기다리지 않고 즉시 돌아옵니다.

t1.join() t1이 종료 될 때까지 t2를 중지시키는 것을 의미합니까?

아니요 호출 t1.join()중인 기본 스레드는 실행을 중지하고 t1스레드가 완료 될 때까지 기다립니다 . t2쓰레드가 병렬로 실행에 의해 영향을받지 않는다 t1거나t1.join() 전혀 호출.

은 try / 캐치의 측면에서,이 join()던졌습니다InterruptedException 는 호출중인 기본 스레드 join()자체가 다른 스레드에 의해 중단 될 수 있음을 의미합니다 .

while (true) {

while루프에 조인을 갖는 것은 이상한 패턴입니다. 일반적으로 첫 번째 조인을 수행 한 다음 두 번째 조인을 수행하여InterruptedException 각 경우에 적절하게 . 루프에 넣을 필요가 없습니다.


24
+1 매우 이상한 패턴이며 아마도 제거 될 수 있습니다.
m0skit0

3
t1이 먼저 완료되면 t2가 완료됩니다. 그것은 순차적 인 과정 인 것 같습니다. 하나의 스레드가 먼저 완료되고 다른 스레드가 완료됩니다. 다중 스레딩의 요점은 무엇입니까?
user697911

9
t1t2병렬로 실행할 수 있기 때문 입니다. main계속하기 전에 둘 다 끝내야 한다는 것 뿐입니다 . 이것이 일반적인 패턴 @ user697911입니다.
Gray

3
while(내 생각)가 재 시도를 원하기 때문에 루프가 join()하나가 중단 된 경우 전화를? 필자는 @ user697911과 같이 작성하지 않을 것입니다.
Gray

5
루프는 마무리 t1t2마무리 를 모두 보장합니다 . 즉. 를 t1던지면, InterruptedException루프백하고 기다립니다 t2. 다른 방법은 각각의 Try-Catch에서 두 스레드를 기다리는 것이므로 루프를 피할 수 있습니다. 또한에 따라 EventThread스레드가 아닌 2 개의 스레드를 실행 하므로이 방법을 사용하는 것이 좋습니다.
Michael Bisbjerg 2016 년

68

이것은 가장 좋아하는 Java 인터뷰 질문입니다.

Thread t1 = new Thread(new EventThread("e1"));
t1.start();
Thread e2 = new Thread(new EventThread("e2"));
t2.start();

while (true) {
    try {
        t1.join(); // 1
        t2.join(); // 2  These lines (1,2) are in in public static void main
        break;
    }
}

t1.join()t1은 " 나는 먼저 끝내고 싶다 "와 같은 것을 말한다 . 의 경우도 마찬가지입니다 t2. 누가 시작 t1했거나 t2스레드 (이 경우에는 main메소드) 에 관계없이 main은 작업을 완료 t1하고 t2완료 할 때까지 기다립니다 .

그러나 중요한 점은 아래로주의해야 할, t1그리고 t2스스로 에 관계없이 병렬로 실행 호출 순서에 가입하실 수 있습니다t1t2. 기다려야main/daemon스레드입니다 .


3
좋은 예입니다. "병행으로 실행할 수있다": 그렇다면 무엇? 메인 스레드가 t1을 먼저 FIRST를 대기하고 t2를 tN을 기다리는 것이 중요합니다. t1 또는 t2가 무엇을하고 있는지는 중요하지 않습니다 (주 스레드 관점에서)
Alex

1
"메인 / 데몬"스레드를 언급했습니다. 내가 이해하는 주체이지만 데몬은 그와 관련이 없습니다. 메인 스레드는 비 데몬입니다.
Gray

1
t1.join(); t2.join();두 스레드가 모두 종료 될 때까지 조인을 실행하는 스레드가 계속되도록 허용하지 않습니다. 다른 곳에서 매우 이례적인 코드가 없으면 조인 순서는 중요하지 않습니다.
David Schwartz

t1이 끝났을 때만 t2.join ()이 호출됩니까?
Leo Droidcoder

다시 말해, t1 및 t2 스레드의 실행을 "직렬화"하려면 주 스레드가 t1을 시작한 이후 (t2 이후에) t1.start () 바로 뒤에 t1.join ()을 배치해야합니다. 시도 / 잡기. 분명히 그렇게하면 병렬 처리가 손실됩니다.
dobrivoje

47

join()스레드가 완료되기를 기다리는 것을 의미합니다. 이것은 차단 방법입니다. 메인 스레드 (을 수행하는 스레드 join())는 작업이 완료 t1.join()될 때까지 줄 을 기다린 t1다음 동일한 작업을 수행합니다 t2.join().


29

그림은 천 단어의 가치가 있습니다.

    Main thread-->----->--->-->--block##########continue--->---->
                 \                 |               |
sub thread start()\                | join()        |
                   \               |               |
                    ---sub thread----->--->--->--finish    

유용한 정보를 원하시면 여기를 클릭 하십시오


3
명확하고 정확합니다.
dobrivoje

10

스레드 tA가 tB.join ()을 호출하면 tB가 죽을 때까지 기다리거나 tA 자체가 인터럽트 될뿐만 아니라 tB의 마지막 명령문과 tA 스레드의 tB.join () 뒤의 다음 명령문 사이의 관계 전에 발생합니다.

스레드의 모든 작업은 다른 스레드가 해당 스레드의 join ()에서 성공적으로 반환되기 전에 발생합니다.

프로그램을 의미한다

class App {
    // shared, not synchronized variable = bad practice
    static int sharedVar = 0;
    public static void main(String[] args) throws Exception {
        Thread threadB = new Thread(() -> {sharedVar = 1;});
        threadB.start();
        threadB.join();

        while (true) 
            System.out.print(sharedVar);
    }
}

항상 인쇄

>> 1111111111111111111111111 ...

그러나 프로그램

class App {
    // shared, not synchronized variable = bad practice
    static int sharedVar = 0;
    public static void main(String[] args) throws Exception {
        Thread threadB = new Thread(() -> {sharedVar = 1;});
        threadB.start();
        // threadB.join();  COMMENT JOIN

        while (true)
            System.out.print(sharedVar);
    }
}

뿐만 아니라 인쇄 할 수 있습니다

>> 0000000000 ... 000000111111111111111111111111 ...

그러나

>> 00000000000000000000000000000000000000000000 ... 

항상 '0'입니다.

Java 메모리 모델은 관계 이전 (스레드 시작, 스레드 조인, 'synchonized'키워드 사용, AtomicXXX 변수 사용 등)없이 threadB에서 기본 스레드로 'sharedVar'의 새로운 값을 '전송'할 필요가 없기 때문입니다.


5

간단히 말하면 완료
t1.join()후 반환 t1됩니다.
thread t1가 끝나기를 기다리는 것을 제외하고 thread에 아무것도하지 않습니다 .
당연히 코드 추적 t1.join()t1.join()반환 후에 만 실행됩니다 .


1
단지 t1.join () 후에 실행됩니다 것은 +1 반환
mohsen.nour

3

조인의 Oracle 설명서 페이지에서

join방법을 사용하면 한 스레드가 다른 스레드의 완료를 기다릴 수 있습니다.

t1이 Thread스레드가 현재 실행중인 객체 인 경우

t1.join() : causes the current thread to pause execution until t1's thread terminates.

t2가 Thread스레드가 현재 실행중인 객체 인 경우

t2.join(); causes the current thread to pause execution until t2's thread terminates.

joinAPI는 이전 버전의 Java에서 도입 된 저수준 API입니다. 동시성에서 일정 기간 동안 (특히 jdk 1.5 릴리스에서) 많은 것들이 변경되었습니다.

java.util.concurrent API를 사용하여 동일한 결과를 얻을 수 있습니다. 예제 중 일부는

  1. 사용 invokeAll을을ExecutorService
  2. CountDownLatch 사용
  3. 사용 ForkJoinPool 또는 newWorkStealingPool 의을 Executors(자바 8부터)

관련 SE 질문을 참조하십시오.

모든 스레드가 Java에서 작업을 완료 할 때까지 기다립니다.


1

나를 위해, 누가 누구를 기다릴 것인지 기억하려고했기 때문에 Join () 동작은 항상 혼란 스러웠습니다. 그렇게 기억하지 마십시오.

그 아래에는 순수한 wait () 및 notify () 메커니즘이 있습니다.

우리는 모든 객체 (t1)에서 wait ()를 호출하면 호출 객체 (main)가 대기실 (Blocked state)로 전송된다는 것을 알고 있습니다.

여기서 주요 스레드는 커버 아래에서 wait () 인 join ()을 호출합니다. 따라서 메인 스레드는 알림을받을 때까지 기다립니다. t1은 실행이 완료되면 (스레드 완료) 알림을받습니다.

알림을받은 후 메인은 대기실에서 나와 실행을 진행합니다.


0

그것이 도움이되기를 바랍니다!

package join;

public class ThreadJoinApp {

    Thread th = new Thread("Thread 1") {
        public void run() {
            System.out.println("Current thread execution - " + Thread.currentThread().getName());
            for (int i = 0; i < 10; i++) {
                System.out.println("Current thread execution - " + Thread.currentThread().getName() + " at index - " + i);
            }
        }
    };

    Thread th2 = new Thread("Thread 2") {
        public void run() {
            System.out.println("Current thread execution - " + Thread.currentThread().getName());

            //Thread 2 waits until the thread 1 successfully completes.
            try {
            th.join();
            } catch( InterruptedException ex) {
                System.out.println("Exception has been caught");
            }

            for (int i = 0; i < 10; i++) {
                System.out.println("Current thread execution - " + Thread.currentThread().getName() + " at index - " + i);
            }
        }
    };

    public static void main(String[] args) {
        ThreadJoinApp threadJoinApp = new ThreadJoinApp();
        threadJoinApp.th.start();
        threadJoinApp.th2.start();
    }

    //Happy coding -- Parthasarathy S
}

-3

메인 스레드가 스레드 t1과 t2를 시작한다고 가정 해 봅시다. 이제 t1.join ()이 호출되면 스레드 t1이 죽을 때까지 메인 스레드가 일시 중단 된 다음 다시 시작됩니다. 마찬가지로 t2.join ()이 실행될 때 스레드 t2가 죽을 때까지 메인 스레드가 다시 일시 중단 된 다음 다시 시작됩니다.

이것이 작동하는 방식입니다.

또한 while 루프는 실제로 필요하지 않았습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.