program tip

자바 멀티 스레딩 개념 및 join () 메서드

radiobox 2020. 12. 28. 08:01
반응형

자바 멀티 스레딩 개념 및 join () 메서드


join()Java의 스레드에서 사용되는 방법이 혼란 스럽습니다 . 다음 코드에서 :

// Using join() to wait for threads to finish.
class NewThread implements Runnable {

    String name; // name of thread
    Thread t;

    NewThread(String threadname) {
        name = threadname;
        t = new Thread(this, name);
        System.out.println("New thread: " + t);
        t.start(); // Start the thread
    }
// This is the entry point for thread.

    public void run() {
        try {
            for (int i = 5; i > 0; i--) {
                System.out.println(name + ": " + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            System.out.println(name + " interrupted.");
        }
        System.out.println(name + " exiting.");
    }
}

class DemoJoin {

    public static void main(String args[]) {
        NewThread ob1 = new NewThread("One");
        NewThread ob2 = new NewThread("Two");
        NewThread ob3 = new NewThread("Three");
        System.out.println("Thread One is alive: "
                + ob1.t.isAlive());
        System.out.println("Thread Two is alive: "
                + ob2.t.isAlive());
        System.out.println("Thread Three is alive: "
                + ob3.t.isAlive());
// wait for threads to finish
        try {
            System.out.println("Waiting for threads to finish.");
            ob1.t.join();
            ob2.t.join();
            ob3.t.join();
        } catch (InterruptedException e) {
            System.out.println("Main thread Interrupted");
        }
        System.out.println("Thread One is alive: "
                + ob1.t.isAlive());
        System.out.println("Thread Two is alive: "
                + ob2.t.isAlive());
        System.out.println("Thread Three is alive: "
                + ob3.t.isAlive());
        System.out.println("Main thread exiting.");
    }
}

이 프로그램의 샘플 출력은 다음과 같습니다.

New thread: Thread[One,5,main]
New thread: Thread[Two,5,main]
New thread: Thread[Three,5,main]
Thread One is alive: true
Thread Two is alive: true
Thread Three is alive: true
Waiting for threads to finish.
One: 5
Two: 5
Three: 5
One: 4
Two: 4
Three: 4
One: 3
Two: 3
Three: 3
One: 2
Two: 2
Three: 2
One: 1
Two: 1
Three: 1
Two exiting.
Three exiting.
One exiting.
Thread One is alive: false
Thread Two is alive: false
Thread Three is alive: false
Main thread Exiting

위의 코드에서 :

  1. 프로그램의 실행 흐름을 이해할 수없고, ob1생성되면 생성자 t.start()가 작성된 위치에서 호출 되지만 여전히 run()메서드가 실행되지 않고 main()메서드가 계속 실행됩니다. 그렇다면 왜 이런 일이 발생합니까?

  2. join() 메서드는 호출 된 스레드가 종료되지 않을 때까지 대기하는 데 사용되지만 여기 출력에서 ​​스레드의 대체 출력이 표시되는 이유는 무엇입니까 ??

그리고 사용 join이 이것이라면 무엇 synchronized입니까 ??

여기에 기본 개념이 누락 된 것을 알고 있지만 이해할 수 없으므로 도와주세요.


스레드 스케줄링은 스레드 스케줄러에 의해 제어되므로 정상적인 상황에서는 스레드 실행 순서를 보장 할 수 없습니다.

그러나 join()스레드가 작업을 완료 할 때까지 대기 하는 사용할 수 있습니다 .

예를 들어, 귀하의 경우

ob1.t.join();

이 문은 스레드 t실행이 완료 될 때까지 반환되지 않습니다 .

이 시도,

class Demo {
   Thread t = new Thread(
                 new Runnable() {
                     public void run () {
                         //do something
                     }
                  }
    );
    Thread t1 = new Thread(
                 new Runnable() {
                     public void run () {
                         //do something
                     }
                  }
    );
    t.start(); // Line 15
    t.join();  // Line 16
    t1.start();
}

위의 예에서 메인 스레드가 실행 중입니다. 줄 15를 만나면 스레드 스케줄러에서 스레드 t를 사용할 수 있습니다. 주 스레드가 16 행에 오자마자 스레드 t가 완료 될 때까지 기다립니다 .

t.join스레드 아무것도하지 않았다 t또는 스레드하기를 t1. 호출 한 스레드 (즉, main()스레드) 에만 영향을 미쳤습니다 .

편집 :

t.join();요구 사항은 내부에하는 try그것 때문에 블록 그렇지 않으면 당신은 컴파일시에 오류가 발생합니다, 예외입니다. 따라서 다음과 같아야합니다.throwsInterruptedException

try{
    t.join();
}catch(InterruptedException e){
    // ...
}

우선 생성 할 때 ob1생성자가 호출되고 실행이 시작됩니다. 그 당시에 t.start()도 별도의 스레드에서 실행됩니다. 새 스레드가 생성 될 때 주 스레드와 병렬로 실행된다는 점을 기억하십시오. 이것이 바로 다음 문으로 메인 실행을 다시 시작하는 이유입니다.

그리고 Join()문은 자식 스레드가 고아 가되는 것을 방지하는 데 사용 됩니다. join(), 메인 클래스에서 호출하지 않으면 메인 스레드가 실행 후 종료되고 자식 스레드가 여전히 명령문을 실행합니다. Join()모든 자식 스레드가 실행을 완료 할 때까지 기다린 다음 메인 메서드 만 종료됩니다.

를 통해 이동 기사 많은 도움이됩니다.


나는 프로그램의 실행 흐름을 이해할 수 없으며, ob1이 생성되면 생성자가 t.start ()가 작성된 곳에서 호출되지만 여전히 run () 메서드가 실행되지 않고 main () 메서드가 계속 실행됩니다. 그렇다면 왜 이런 일이 발생합니까?

main은 동일한 우선 순위를 공유하므로 Thread Scheduler에 따라 다릅니다. start ()를 호출한다고해서 run ()이 즉시 호출되는 것은 아니며 스레드를 실행하기로 선택할 때 스레드 스케줄러에 따라 다릅니다.

join () 메서드는 호출 된 스레드가 종료되지 않을 때까지 대기하는 데 사용되지만 여기 출력에서 ​​스레드의 대체 출력이 표시되는 이유는 무엇입니까 ??

이것은 코드의 Thread.sleep (1000) 때문입니다. 해당 줄을 제거하면 ob1이 ob2보다 먼저 끝나고 ob3보다 먼저 끝나는 것을 볼 수 있습니다 (join ()로 예상 한대로). 그것은 모두 ob1 ob2와 ob3이 시작된시기에 달려 있다고 말했습니다. sleep을 호출하면 코드에서> = 1 초 동안 스레드 실행이 일시 중지되어 스케줄러가 대기중인 다른 스레드를 호출 할 수 있습니다 (동일한 우선 순위).


스레딩의 첫 번째 규칙- "스레딩은 재미 있습니다"...

나는 프로그램의 실행 흐름을 이해할 수 없으며, ob1이 생성되면 생성자 t.start()가 작성된 위치 호출 되지만 여전히 run()메서드가 실행되지 않고 main()메서드가 계속 실행됩니다. 그렇다면 왜 이런 일이 발생합니까?

이것이 정확히 일어날 일입니다. 을 호출 Thread#start하면 스레드가 생성되고 실행 일정이 잡히면 즉시 (또는 충분히 가깝게) 발생할 수 있지만 그렇지 않을 수도 있습니다. 스레드 스케줄러로 내려갑니다.

이것은 스레드 실행이 예약되는 방법과 시스템에서 다른 작업이 진행되는 방식에 달려 있습니다. 일반적으로 각 스레드는 "휴면"상태로 돌아가고 다른 스레드가 실행되기 전에 실행하는 데 약간의 시간이 주어집니다 (분명히 여러 프로세서 환경에서 한 번에 둘 이상의 스레드가 실행될 수 있지만 시도해 봅시다). 간단하게 유지하십시오;))

스레드는 또한 yield실행될 수 있으며 시스템의 다른 스레드가 실행할 기회를 가질 수 있습니다.

당신은 시도 할 수 있습니다

NewThread(String threadname) {
    name = threadname;
    t = new Thread(this, name);
    System.out.println("New thread: " + t);
    t.start(); // Start the thread
    // Yield here
    Thread.yield();
}

그리고 스레드가 실행되는 방식에 차이를 만들 수 있습니다. 똑같이 sleep짧은 시간 동안은 가능하지만 이로 인해 스레드가 일정주기 동안 실행되지 않을 수 있습니다 (때로는 이것을 원합니다. 하지마) ...

join() 메서드는 호출 된 스레드가 종료되지 않을 때까지 대기하는 데 사용되지만 여기 출력에서 ​​스레드의 대체 출력이 표시되는 이유는 무엇입니까 ??

질문이 틀렸다고 말한 방식 은 돌아 오기 전에 죽도록 요청 join받은 Thread것을 기다릴 것입니다. 예를 들어의 결과에 의존하는 경우를 Thread사용 join하여 Thread결과를 검색하기 전에이 종료 된 시기를 알 있습니다.

동일하게 스레드를 폴링 할 수 있지만 Thread대신에 더 잘 사용할 수있는 CPU 사이클을 먹습니다 .


JVM과 기본 OS는 일정을 계획 할 때 상당한 자유를가집니다. 개별 스레드의 출력을보기 전에 "스레드가 완료 될 때까지 대기"까지 끝까지 도달한다는 사실은 단순히 스레드 시작이 약간 더 오래 걸린다는 것을 의미 할 수 있습니다 (즉, 스레드가 "가되는 순간 사이에 약간의 시간이 걸립니다." alive "및 run () 메서드가 실제로 실행을 시작할 때). 스레드 출력을 더 빨리 볼 수 있지만 어느 쪽이든 보장되지는 않습니다.

join ()에 관해서는 , 당신이 조인하고있는 쓰레드가 완료된 후에 만 ​​그 이후의 모든 일이 일어나도록 보장합니다. 따라서 연속으로 3 개의 join () 호출이 있다고해서 스레드가 특정 순서로 끝나야한다는 의미는 아닙니다. 단순히 ob1을 먼저 기다릴 것임을 의미합니다 . 일단 OB1 완료, OB2ob3 계속 실행 할 수있다거나 이미 완료 할 수있다. 완료되면 다른 join () 호출이 즉시 반환됩니다.

동기화 는 특히 여러 스레드가 동일한 객체에 액세스하여 변경하는 경우에 사용됩니다. 동기화 된 블록은 두 스레드에 의해 동시에 실행되지 않도록 보장됩니다. 즉,이를 실행하는 스레드는 동기화 된 객체를 모두 가지고 있습니다.


ob1이 생성되면 생성자는 "t.start ()"가 쓰여진 곳에서 호출되지만 여전히 run () 메서드는 실행되지 않고 main () 메서드가 더 실행됩니다. 그렇다면 왜 이런 일이 발생합니까?

여기서 당신의 쓰레드와 메인 쓰레드는 동일한 우선 순위를 가지고 있습니다. 동일한 우선 순위 쓰레드의 실행은 전적으로 Thread schedular. 당신은 먼저 실행할 것을 기대할 수 없습니다.

join () 메서드는 호출 된 스레드가 종료되지 않을 때까지 대기하는 데 사용되지만 여기 출력에서 ​​스레드의 대체 출력이 표시되는 이유는 무엇입니까 ??

여기에 주 스레드에서 아래 명령문을 호출하십시오.

     ob1.t.join();
     ob2.t.join();
     ob3.t.join();

에 대한 그래서 메인 스레드 대기 ob1.t, ob2.t, ob3.t스레드가 죽을 (조사 스레드 #이 문서에 가입 성공적으로 세 개의 스레드가 실행 낭포) 그 후 메인 스레드 완료


내 의견 :

출력을 보면 출력이 스레드 이름 인 One, Two, Three와 혼합되어 동시에 실행됩니다. 스레드가 주 방법으로 실행되고 있지 않다고 말할 때 확실하지 않습니다.

귀하의 질문을 이해했는지 확실하지 않습니다. 그러나 나는 내가 이해할 수있는 것에 대한 대답을하고있다. 그것이 당신을 도울 수 있기를 바란다.

1) 그런 다음 생성자라고 부르는 객체를 생성했으며, 구조체에는 스레드를 시작하고 run () 메서드 내에 작성된 내용을 실행하는 시작 메서드가 있습니다.

따라서 3 개의 개체 (3 개의 스레드-1, 2, 3 개)를 만들면 3 개의 스레드가 모두 동시에 실행되기 시작했습니다.

2) Join과 Synchronization 서로 다른 두 가지입니다. Synchronization은 공통 자원을 공유하는 여러 스레드가 있고 한 번에 하나의 스레드가 해당 자원을 사용해야하는 경우입니다. 예를 들어 DepositThread, WithdrawThread 등과 같은 스레드는 BankObject와 같은 공통 객체를 공유합니다. 따라서 DepositThread가 실행되는 동안 WithdrawThread는 동기화되면 대기합니다. wait (), notify (), notifyAll ()은 스레드 간 통신에 사용됩니다. Plz Google은 더 많은 것을 알고 있습니다.

Join ()에 대해 여러 스레드가 실행 중이지만 참여할 때입니다. 예를 들어 두 개의 스레드 t1 및 t2가 있고 다중 스레드 환경에서 실행되는 경우 출력은 다음과 같습니다. t1-0 t2-0 t1-1 t2-1 t1-2 t2-2

그리고 우리는 t1.join ()을 사용합니다. t1-0 t1-1 t1-2 t2-0 t2-1 t2-2

때때로 특정 조건에서 스레드를 혼합하지 않고 하나가 완료되기 위해 다른 스레드에 의존 할 때 (공유 리소스가 아닌) 실시간으로 사용되므로 join () 메서드를 호출 할 수 있습니다.


스레드 스케줄러는 스레드 스케줄링을 담당합니다. 따라서 프로그램을 실행할 때마다 스레드 실행 순서가 보장되지 않습니다. threadOne이라는 스레드 객체가 있고 다음과 같이 threadOne에서 join ()이 호출되었다고 가정합니다.

threadOne.join ()

그러면 현재 실행중인 모든 스레드는 thread1이 실행을 완료하거나 종료 할 때까지 일시 중지됩니다.

다음 코드를 고려하십시오.

class RunnableSample implements Runnable {
    private Thread t;
    private String threadName;

    public RunnableSample(String name) {
        this.threadName = name;
    }
    public void run() {
        try {
            for(int i = 4; i >= 1; i--) {
                System.out.println(Thread.currentThread().getName() + ", " + i);
            Thread.sleep(500);
            }
        } catch (InterruptedException e) {
            System.out.println(threadName + " interrupted");
        }
    }
    public void start() {
        if(t == null)
            t = new Thread(this, threadName);
        t.start();
        try {
            t.join();
        } catch(Exception e) {
            System.out.println(e);
        }
    }
}
public class RunnableDemo {
    public static void main(String[] args) {
        RunnableSample r1 = new RunnableSample("threadOne");
        r1.start();

        RunnableSample r2 = new RunnableSample("threadTwo");
        r2.start();

        RunnableSample r3 = new RunnableSample("threadThree");
        r3.start();
     }
}

위 프로그램의 출력은 다음과 같습니다.

threadOne, 4
threadOne, 3
threadOne, 2
threadOne, 1
threadTwo, 4
threadTwo, 3
threadTwo, 2
threadTwo, 1
threadThree, 4
threadThree, 3
threadThree, 2
threadThree, 1

join ()이 threadOne에서 먼저 호출되므로 threadOne이 종료 될 때까지 threadTwo 및 threadThree가 일시 중지됩니다. (threadOne, threadTwo 및 ThreadThree가 모두 시작되었습니다.) 이제 스레드가 특정 순서로 실행됩니다. 이 예제의 스레드에서 join ()이 호출되지 않으면 스레드 실행 순서가 없습니다.

public void start() {
    if(t == null)
        t = new Thread(this, threadName);
    t.start();
}

출력은 다음과 같습니다.

threadOne, 4
threadThree, 4
threadTwo, 4
threadTwo, 3
threadThree, 3
threadOne, 3
threadOne, 2
threadThree, 2
threadTwo, 2
threadOne, 1
threadThree, 1
threadTwo, 1

공유 리소스에서 여러 스레드의 액세스를 제어하려는 경우 유용합니다. 하나의 스레드 만 공유 리소스에 액세스하도록 제한하려면 동기화가 가장 좋은 방법입니다.


코드를 실행하는 단어 없음

// Thread class
public class MyThread extends Thread {

    String result = null;

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

    public void run() {
        for (int i = 0; i < 1000; i++) {

            System.out.println("Hello from " + this.getName());
        }
        result = "Bye from " + this.getName();
    }
}

메인 클래스

public class JoinRND {
    public static void main(String[] args) {

        System.out.println("Show time");
        // Creating threads
        MyThread m1 = new MyThread("Thread M1");
        MyThread m2 = new MyThread("Thread M2");
        MyThread m3 = new MyThread("Thread M3");

        // Starting out Threads
        m1.start();
        m2.start();
        m3.start();
        // Just checking current value of thread class variable
        System.out.println("M1 before: " + m1.result);
        System.out.println("M2 before: " + m2.result);
        System.out.println("M3 before: " + m3.result);
        // After starting all threads main is performing its own logic in
        // parallel to other threads
        for (int i = 0; i < 1000; i++) {

            System.out.println("Hello from Main");
        }

        try {

            System.out
                    .println("Main is waiting for other threads to get there task completed");
            m1.join();
            m2.join();
            m3.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("M1 after" + m1.result);
        System.out.println("M2 after" + m2.result);
        System.out.println("M3 after" + m3.result);

        System.out.println("Show over");
    }
}

나는 경쟁 조건에 대해 배우면서 join ()을 발견했고 내가 가지고 있던 의심을 제거 할 것이다. 이 작은 예를 들어 보겠습니다.

Thread t2 = new Thread(
             new Runnable() {
                 public void run () {
                     //do something
                 }
              }
);
Thread t1 = new Thread(
             new Runnable() {
                 public void run () {
                     //do something
                 }
              }
);
t2.start(); //Line 11
t1.start(); //Line 12
t2.join();  //Line 13
t1.join();  //Line 14
System.out.print("<Want to print something that was being modified by t2 and t1>")

My AIM
Three 스레드는 t1, t2 및 메인 스레드를 실행합니다. t1과 t2가 완료된 후에 무언가를 인쇄하고 싶습니다. 인쇄 작업은 내 주 스레드에 있으므로 예상 답변에 대해 t1 및 t2를 완료 한 다음 출력을 인쇄해야합니다.

따라서 t1.join ()은 프로그램의 다음 줄로 이동하기 전에 t1 스레드가 완료 될 때까지 메인 스레드를 대기시킵니다.

다음은 GeeksforGeeks에 따른 정의입니다 .

java.lang.Thread 클래스는 다른 스레드가 실행을 완료 할 때까지 한 스레드가 대기 할 수 있도록하는 join () 메소드를 제공합니다.

의심을 해결할 수있는 한 가지 질문이 있습니다.

Q-> 프로그램이 13 행 에서 t2.join ()을 처리 할 때 t1 스레드가 스레드 스케줄러가 실행할 타임 슬라이스를 얻 습니까?

ANS-> 예, 11 행에서 t1.start () 라인을 실행하여 이미 적격하게 만들었으므로 타임 슬라이스를 실행할 수 있습니다 .
t2.join ()은 JVM이 다음 행인 14 행으로 이동할 때만 조건을 적용합니다.
t1이 13 행 에서 처리를 완료 할 수도 있습니다 .


join ()은 java.lang.Thread 클래스의 인스턴스 메소드로 main에서 시작된 모든 스레드가 시작된 순서대로 끝나야하고 main이 마지막으로 끝나도록하기 위해 join () 메소드를 사용할 수 있습니다. 즉,이 스레드가 죽을 때까지 기다립니다.

예외 : join () 메서드에서 InterruptedException이 발생합니다.

스레드 상태 : 스레드에서 join () 메서드가 호출되면 실행 중 상태에서 대기 상태로 바뀝니다. 그리고 실이 죽을 때까지 기다리십시오.

동기화 된 블록 : 스레드는 join () 메서드를 호출하기 전에 객체 잠금을 획득 할 필요가 없습니다. 즉, 동기화 된 블록 외부에서 join () 메서드를 호출 할 수 있습니다.

대기 시간 : join () :이 스레드가 죽기를 기다립니다.

public final void join() throws InterruptedException;

이 메서드는 내부적으로 join (0)을 호출합니다. 시간 초과 0은 영원히 대기한다는 의미입니다.

join (long millis) – 동기화 된 메서드이 스레드가 죽을 때까지 최대 밀리 초를 기다립니다. 시간 초과 0은 영원히 대기 함을 의미합니다.

public final synchronized void join(long millis)
    throws InterruptedException;

public final synchronized void join(long millis, int nanos)
    throws InterruptedException;

결합 방법의 예

class MyThread implements Runnable {
     public void run() {
           String threadName = Thread.currentThread().getName();
           Printer.print("run() method of "+threadName);
           for(int i=0;i<4;i++){
                Printer.print("i="+i+" ,Thread="+threadName);
           }         
     }
}

public class TestJoin {
     public static void main(String...args) throws InterruptedException {
           Printer.print("start main()...");

           MyThread runnable = new MyThread();
           Thread thread1=new Thread(runnable);
           Thread thread2=new Thread(runnable);

           thread1.start();
           thread1.join();

           thread2.start();
           thread2.join();

           Printer.print("end main()");
     }
}

class Printer {
     public static void print(String str) {
           System.out.println(str);
     }
}

Output:
     start main()...
     run() method of Thread-0
     i=0 ,Thread=Thread-0
     i=1 ,Thread=Thread-0
     i=2 ,Thread=Thread-0
     i=3 ,Thread=Thread-0
     run() method of Thread-1
     i=0 ,Thread=Thread-1
     i=1 ,Thread=Thread-1
     i=2 ,Thread=Thread-1
     i=3 ,Thread=Thread-1
     end main()

참고 : thread1.join ()을 호출하면 Thread-1이 죽을 때까지 메인 스레드가 대기하게됩니다.

join (long millis)을 사용하는 프로그램을 확인해 봅시다.

첫째, join (1000)은 Thread-1에서 호출되지만 1000 밀리 초가 작동하면 주 스레드가 다시 시작되고 thread2를 시작할 수 있습니다 (주 스레드는 Thread-1이 죽을 때까지 기다리지 않습니다).

class MyThread implements Runnable {
     public void run() {
           String threadName = Thread.currentThread().getName();
           Printer.print("run() method of "+threadName);
           for(int i=0;i<4;i++){
                try {
                     Thread.sleep(500);
                } catch (InterruptedException e) {
                     e.printStackTrace();
                }
                Printer.print("i="+i+" ,Thread="+threadName);
           }         
     }
}

public class TestJoin {
     public static void main(String...args) throws InterruptedException {
           Printer.print("start main()...");

           MyThread runnable = new MyThread();
           Thread thread1=new Thread(runnable);
           Thread thread2=new Thread(runnable);

           thread1.start();

           // once 1000 millisec are up,
           // main thread can resume and start thread2.
           thread1.join(1000);

           thread2.start();
           thread2.join();

           Printer.print("end main()");
     }
}

class Printer {
     public static void print(String str) {
           System.out.println(str);
     }
}

Output:
     start main()...
     run() method of Thread-0
     i=0 ,Thread=Thread-0
     run() method of Thread-1
     i=1 ,Thread=Thread-0
     i=2 ,Thread=Thread-0
     i=0 ,Thread=Thread-1
     i=1 ,Thread=Thread-1
     i=3 ,Thread=Thread-0
     i=2 ,Thread=Thread-1
     i=3 ,Thread=Thread-1
     end main()

자세한 내용은 내 블로그를 참조하십시오.

http://javaexplorer03.blogspot.in/2016/05/join-method-in-java.html


See the concept is very simple.

1) All threads are started in the constructor and thus are in ready to run state. Main is already the running thread.

2) Now you called the t1.join(). Here what happens is that the main thread gets knotted behind the t1 thread. So you can imagine a longer thread with main attached to the lower end of t1.

3) Now there are three threads which could run: t2, t3 and combined thread(t1 + main).

4)Now since till t1 is finished main can't run. so the execution of the other two join statements has been stopped.

5) So the scheduler now decides which of the above mentioned(in point 3) threads run which explains the output.

ReferenceURL : https://stackoverflow.com/questions/18479771/java-multithreading-concept-and-join-method

반응형