[java] Java 스레드가 다른 스레드의 출력을 기다리는 방법?

application-logic-thread 및 데이터베이스 액세스 스레드로 Java 응용 프로그램을 만들고 있습니다. 둘 다 응용 프로그램의 전체 수명 동안 지속되며 둘 다 동시에 실행되어야합니다 (한 번은 서버와 대화하고 한 번은 사용자와 대화합니다. 앱이 완전히 시작되면 두 가지 모두 작동 해야 합니다 ).

그러나 시작할 때 앱 스레드가 DB 스레드가 준비 될 때까지 (현재는 사용자 정의 방법을 폴링하여 결정) 대기해야합니다 dbthread.isReady(). DB 스레드가 준비 될 때까지 앱 스레드가 차단되는지는 신경 쓰지 않습니다.

Thread.join() 솔루션처럼 보이지 않습니다. db 스레드는 앱 종료시에만 종료됩니다.

while (!dbthread.isReady()) {} 작동하지만 빈 루프는 많은 프로세서주기를 소비합니다.

다른 아이디어가 있습니까? 감사.



답변

마법의 멀티 스레딩 세계에서 시작하기 전에 Sun의 Java Concurrency 와 같은 자습서를 살펴 보는 것이 좋습니다 .

또한 좋은 책들이 많이 있습니다 ( “Java 동시 프로그래밍”, “실제 Java 동시성”).

답을 얻으려면 :

를 기다려야하는 코드 dbThread에는 다음과 같은 내용이 있어야합니다.

//do some work
synchronized(objectYouNeedToLockOn){
    while (!dbThread.isReady()){
        objectYouNeedToLockOn.wait();
    }
}
//continue with work after dbThread is ready

dbThread의 방법으로 다음과 같이해야합니다.

//do db work
synchronized(objectYouNeedToLockOn){
    //set ready flag to true (so isReady returns true)
    ready = true;
    objectYouNeedToLockOn.notifyAll();
}
//end thread run method here

objectYouNeedToLockOn나는이 예제에서 사용하고는 각 스레드에서 동시에 조작해야하는 것이 바람직 객체, 또는 별도의를 만들 수 있습니다 Object(I 자체가 동기화 방법을 권하고 싶지 않다) 그 목적을 위해 :

private final Object lock = new Object();
//now use lock in your synchronized blocks

더 이해하기 위해 :
위와 같은 방법을 사용하는 다른 (때로는 더 나은) 방법이 있습니다. 예를 들어 CountdownLatchesJava 5 이후로 java.util.concurrent패키지와 하위 패키지 에는 많은 멋진 동시성 클래스가 있습니다. 동시성을 알거나 좋은 책을 얻으려면 온라인에서 자료를 찾아야합니다.


답변

카운터가 1 인 CountDownLatch 를 사용하십시오 .

CountDownLatch latch = new CountDownLatch(1);

이제 앱 스레드에서

latch.await();

DB 스레드에서 완료 후-

latch.countDown();


답변

요구 사항 ::

  1. 이전 스레드가 완료 될 때까지 다음 스레드의 실행을 기다립니다.
  2. 다음 스레드는 시간 소비에 관계없이 이전 스레드가 중지 될 때까지 시작해서는 안됩니다.
  3. 간단하고 사용하기 쉬워야합니다.

대답 ::

@ java.util.concurrent.Future.get () 문서를 참조하십시오.

future.get () 필요한 경우 계산이 완료되기를 기다린 다음 결과를 검색합니다.

작업 완료 !! 아래 예를 참조하십시오

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.junit.Test;

public class ThreadTest {

    public void print(String m) {
        System.out.println(m);
    }

    public class One implements Callable<Integer> {

        public Integer call() throws Exception {
            print("One...");
            Thread.sleep(6000);
            print("One!!");
            return 100;
        }
    }

    public class Two implements Callable<String> {

        public String call() throws Exception {
            print("Two...");
            Thread.sleep(1000);
            print("Two!!");
            return "Done";
        }
    }

    public class Three implements Callable<Boolean> {

        public Boolean call() throws Exception {
            print("Three...");
            Thread.sleep(2000);
            print("Three!!");
            return true;
        }
    }

    /**
     * @See java.util.concurrent.Future.get() doc
     *      <p>
     *      Waits if necessary for the computation to complete, and then
     *      retrieves its result.
     */
    @Test
    public void poolRun() throws InterruptedException, ExecutionException {
        int n = 3;
        // Build a fixed number of thread pool
        ExecutorService pool = Executors.newFixedThreadPool(n);
        // Wait until One finishes it's task.
        pool.submit(new One()).get();
        // Wait until Two finishes it's task.
        pool.submit(new Two()).get();
        // Wait until Three finishes it's task.
        pool.submit(new Three()).get();
        pool.shutdown();
    }
}

이 프로그램의 출력 ::

One...
One!!
Two...
Two!!
Three...
Three!!

다른 스레드보다 큰 작업을 완료하기 전에 6 초가 걸린다는 것을 알 수 있습니다. 따라서 Future.get ()은 작업이 완료 될 때까지 기다립니다.

future.get ()을 사용하지 않으면 완료되기를 기다리지 않고 기반 시간 소비를 실행합니다.

Java 동시성에 대한 행운을 빕니다.


답변

많은 정답이 있지만 간단한 예는 없습니다. 다음은 사용하는 쉽고 간단한 방법입니다 CountDownLatch.

//inside your currentThread.. lets call it Thread_Main
//1
final CountDownLatch latch = new CountDownLatch(1);

//2
// launch thread#2
new Thread(new Runnable() {
    @Override
    public void run() {
        //4
        //do your logic here in thread#2

        //then release the lock
        //5
        latch.countDown();
    }
}).start();

try {
    //3 this method will block the thread of latch untill its released later from thread#2
    latch.await();
} catch (InterruptedException e) {
    e.printStackTrace();
}

//6
// You reach here after  latch.countDown() is called from thread#2


답변

public class ThreadEvent {

    private final Object lock = new Object();

    public void signal() {
        synchronized (lock) {
            lock.notify();
        }
    }

    public void await() throws InterruptedException {
        synchronized (lock) {
            lock.wait();
        }
    }
}

이 클래스를 다음과 같이 사용하십시오.

ThreadEvent를 작성하십시오.

ThreadEvent resultsReady = new ThreadEvent();

이 방법에서 결과를 기다리고 있습니다.

resultsReady.await();

그리고 모든 결과가 생성 된 후 결과를 생성하는 방법에서 :

resultsReady.signal();

편집하다:

(이 게시물을 편집 해 주셔서 감사합니다. 그러나이 코드는 경쟁 조건이 매우 좋지 않으며 의견을 말할만한 평판이 없습니다.)

await () 이후에 signal ()이 호출되었다는 100 % 확신이있는 경우에만이를 사용할 수 있습니다. 이것이 Windows 이벤트와 같은 Java 객체를 사용할 수없는 가장 큰 이유입니다.

코드가 다음 순서로 실행되는 경우 :

Thread 1: resultsReady.signal();
Thread 2: resultsReady.await();

다음 스레드 2는 영원히 기다릴 것이다 . Object.notify ()는 현재 실행중인 스레드 중 하나만 깨우기 때문입니다. 나중에 대기중인 스레드는 해제되지 않습니다. 이것은 a) 대기 또는 b) 명시 적으로 재설정 할 때까지 이벤트가 신호를받는 이벤트가 작동하는 방식과 매우 다릅니다.

참고 : 대부분의 경우 notifyAll ()을 사용해야하지만 이는 위의 “영원히 대기”문제와 관련이 없습니다.


답변

패키지에서 CountDownLatch 클래스를 사용해보십시오.이 클래스 java.util.concurrent는 하위 수준보다 오류가 훨씬 적은 상위 수준의 동기화 메커니즘을 제공합니다.


답변

두 스레드간에 공유 되는 Exchanger 개체를 사용하여 수행 할 수 있습니다 .

private Exchanger<String> myDataExchanger = new Exchanger<String>();

// Wait for thread's output
String data;
try {
  data = myDataExchanger.exchange("");
} catch (InterruptedException e1) {
  // Handle Exceptions
}

그리고 두 번째 실에서 :

try {
    myDataExchanger.exchange(data)
} catch (InterruptedException e) {

}

다른 사람들이 말했듯 이이 가벼운 마음으로 복사하여 붙여 넣기 코드를 사용하지 마십시오. 먼저 읽어보십시오.