다른 스레드가 완료되었는지 확인하는 방법은 무엇입니까?
StartDownload()
세 개의 스레드를 시작 하는라는 메소드를 가진 객체가 있습니다.
각 스레드의 실행이 완료되면 알림을 받으려면 어떻게합니까?
스레드 중 하나 (또는 전부)가 완료되었거나 여전히 실행 중인지 알 수있는 방법이 있습니까?
이를 수행 할 수있는 여러 가지 방법이 있습니다.
- 사용 를 Thread.join () 주 스레드에서 각 스레드가 완료 될 때까지 차단 방식으로 기다리거나하는
- 각 스레드가 완료 될 때까지 기다리려면 폴링 방식으로 Thread.isAlive () 를 확인하십시오 ( 일반적으로 권장하지 않음).
- Unorthodox는 문제의 각 스레드에 대해 setUncaughtExceptionHandler 를 호출하여 객체의 메소드를 호출하고 각 스레드가 완료 될 때 포착되지 않은 예외를 처리하도록 프로그래밍합니다.
- 에서 잠금 또는 싱크로 나이저 또는 메커니즘을 사용 하고있는 java.util.concurrent , 또는
- 더 많은 정통, 기본 스레드에서 리스너를 만든 다음 각 스레드를 프로그래밍하여 리스너에게 완료되었음을 알리십시오.
아이디어 # 5를 구현하는 방법? 한 가지 방법은 먼저 인터페이스를 만드는 것입니다.
public interface ThreadCompleteListener {
void notifyOfThreadComplete(final Thread thread);
}
그런 다음 다음 클래스를 만듭니다.
public abstract class NotifyingThread extends Thread {
private final Set<ThreadCompleteListener> listeners
= new CopyOnWriteArraySet<ThreadCompleteListener>();
public final void addListener(final ThreadCompleteListener listener) {
listeners.add(listener);
}
public final void removeListener(final ThreadCompleteListener listener) {
listeners.remove(listener);
}
private final void notifyListeners() {
for (ThreadCompleteListener listener : listeners) {
listener.notifyOfThreadComplete(this);
}
}
@Override
public final void run() {
try {
doRun();
} finally {
notifyListeners();
}
}
public abstract void doRun();
}
그런 다음 각 스레드가 확장 NotifyingThread
되고 구현 run()
하는 대신 구현 doRun()
됩니다. 따라서 완료되면 알림을 기다리는 사람에게 자동으로 알립니다.
마지막으로, 모든 스레드를 시작하는 클래스 (또는 적어도 알림을 기다리는 객체)의 기본 클래스에서 implement ThreadCompleteListener
각 스레드를 생성 한 직후와 즉시 해당 클래스를 리스너 목록에 추가하십시오.
NotifyingThread thread1 = new OneOfYourThreads();
thread1.addListener(this); // add ourselves as a listener
thread1.start(); // Start the Thread
그런 다음 각 스레드가 종료되면 notifyOfThreadComplete
방금 완료되었거나 충돌 한 Thread 인스턴스와 함께 메서드가 호출됩니다.
더 잘 참고하는 것 implements Runnable
보다는 extends Thread
위한 NotifyingThread
스레드를 확장하는 것은 일반적으로 새로운 코드에 낙심 될 때. 그러나 나는 당신의 질문에 코딩하고 있습니다. NotifyingThread
구현 하도록 클래스를 변경하면 Runnable
스레드를 관리하는 코드 중 일부를 변경해야합니다.
CyclicBarrier를 사용한 솔루션
public class Downloader {
private CyclicBarrier barrier;
private final static int NUMBER_OF_DOWNLOADING_THREADS;
private DownloadingThread extends Thread {
private final String url;
public DownloadingThread(String url) {
super();
this.url = url;
}
@Override
public void run() {
barrier.await(); // label1
download(url);
barrier.await(); // label2
}
}
public void startDownload() {
// plus one for the main thread of execution
barrier = new CyclicBarrier(NUMBER_OF_DOWNLOADING_THREADS + 1); // label0
for (int i = 0; i < NUMBER_OF_DOWNLOADING_THREADS; i++) {
new DownloadingThread("http://www.flickr.com/someUser/pic" + i + ".jpg").start();
}
barrier.await(); // label3
displayMessage("Please wait...");
barrier.await(); // label4
displayMessage("Finished");
}
}
label0- 주기적 스레드는 실행 스레드 수와 기본 실행 스레드 당 하나 (startDownload ()가 실행중인 스레드 수)에 동일한 당사자 수로 작성됩니다.
라벨 1 -n 번째 다운로드 스레드가 대기실에 들어갑니다.
라벨 3 -NUMBER_OF_DOWNLOADING_THREADS가 대기실에 입장했습니다. 주요 실행 스레드는 거의 동시에 다운로드 작업을 시작하기 위해 릴리스합니다.
레이블 4- 주요 실행 스레드가 대기실에 들어갑니다. 이것은 이해하기 쉬운 코드 중 가장 까다로운 부분입니다. 대기실에 두 번째 스레드가 들어가는 것은 중요하지 않습니다. 마지막으로 방에 들어가는 스레드가 있으면 다른 모든 다운로드 스레드가 다운로드 작업을 완료했는지 확인하는 것이 중요합니다.
라벨 2 -n 번째 다운로드 중 스레드가 다운로드 작업을 마치고 대기실로 들어갑니다. 그것이 메인 실행 스레드를 포함하여 이미 NUMBER_OF_DOWNLOADING_THREADS에 들어간 마지막 스레드 인 경우 메인 스레드는 다른 모든 스레드가 다운로드를 완료 한 경우에만 실행을 계속합니다.
당신은해야 정말 사용하는 솔루션을 선호합니다 java.util.concurrent
. 주제에서 Josh Bloch 및 / 또는 Brian Goetz를 찾아 읽으십시오.
java.util.concurrent.*
스레드를 직접 사용 하지 않고 직접 사용 join()
하는 경우 스레드가 완료된 시점을 알아야합니다. 다음은 매우 간단한 콜백 메커니즘입니다. 먼저 Runnable
인터페이스를 확장하여 콜백을 갖습니다.
public interface CallbackRunnable extends Runnable {
public void callback();
}
그런 다음 런너 블을 실행할 실행자를 만들고 완료되면 다시 전화하십시오.
public class CallbackExecutor implements Executor {
@Override
public void execute(final Runnable r) {
final Thread runner = new Thread(r);
runner.start();
if ( r instanceof CallbackRunnable ) {
// create a thread to perform the callback
Thread callerbacker = new Thread(new Runnable() {
@Override
public void run() {
try {
// block until the running thread is done
runner.join();
((CallbackRunnable)r).callback();
}
catch ( InterruptedException e ) {
// someone doesn't want us running. ok, maybe we give up.
}
}
});
callerbacker.start();
}
}
}
CallbackRunnable
인터페이스 에 추가해야 할 또 다른 분명한 것은 예외를 처리하는 수단이므로, public void uncaughtException(Throwable e);
거기에 행을 넣고 실행기에 Thread.UncaughtExceptionHandler를 설치하여 해당 인터페이스 메소드로 보내십시오.
그러나 실제로 모든 냄새를 맡기 시작합니다 java.util.concurrent.Callable
. java.util.concurrent
프로젝트에서 허용하는 경우 실제로 사용을 살펴 봐야 합니다.
그들이 끝날 때까지 기다리시겠습니까? 그렇다면 Join 메서드를 사용하십시오.
확인하려는 경우 isAlive 속성도 있습니다.
getState ()로 스레드 인스턴스를 조사하여 다음 값 중 하나를 사용하여 Thread.State 열거의 인스턴스를 리턴합니다.
* NEW
A thread that has not yet started is in this state.
* RUNNABLE
A thread executing in the Java virtual machine is in this state.
* BLOCKED
A thread that is blocked waiting for a monitor lock is in this state.
* WAITING
A thread that is waiting indefinitely for another thread to perform a particular action is in this state.
* TIMED_WAITING
A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
* TERMINATED
A thread that has exited is in this state.
그러나 3 명의 자식이 완료되기를 기다리는 마스터 스레드를 갖는 것이 더 나은 디자인이라고 생각하고 다른 3 명이 완료되면 마스터는 계속 실행합니다.
Executors
개체를 사용하여 ExecutorService 스레드 풀 을 만들 수도 있습니다. 그런 다음이 invokeAll
방법을 사용하여 각 스레드를 실행하고 선물을 검색하십시오. 모든 실행이 완료 될 때까지 차단됩니다. 다른 옵션은 풀을 사용하여 각각을 실행 한 다음 awaitTermination
풀 실행이 완료 될 때까지 블록 을 호출 하는 것입니다. shutdown
작업 추가가 완료되면 () 로 전화하십시오 .
Thread 클래스 에 대한 javadoc을 보는 것이 좋습니다 .
스레드 조작을위한 여러 메커니즘이 있습니다.
주 스레드
join()
는 3 개의 스레드를 직렬로 연결할 수 있으며 3 개의 스레드가 모두 완료 될 때까지 진행되지 않습니다.생성 된 스레드의 스레드 상태를 간격으로여십시오.
Put all of the spawned threads into a separate
ThreadGroup
and poll theactiveCount()
on theThreadGroup
and wait for it to get to 0.Setup a custom callback or listener type of interface for inter-thread communication.
I'm sure there are plenty of other ways I'm still missing.
Many things have been changed in last 6 years on multi-threading front.
Instead of using join()
and lock API, you can use
1.ExecutorService invokeAll()
API
Executes the given tasks, returning a list of Futures holding their status and results when all complete.
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
A
CountDownLatch
is initialized with a given count. The await methods block until the current count reaches zero due to invocations of thecountDown()
method, after which all waiting threads are released and any subsequent invocations of await return immediately. This is a one-shot phenomenon -- the count cannot be reset. If you need a version that resets the count, consider using a CyclicBarrier.
3.ForkJoinPool or newWorkStealingPool()
in Executors is other way
4.Iterate through all Future
tasks from submit on ExecutorService
and check the status with blocking call get()
on Future
object
Have a look at related SE questions:
How to wait for a thread that spawns it's own thread?
Executors: How to synchronously wait until all tasks have finished if tasks are created recursively?
Here's a solution that is simple, short, easy to understand, and works perfectly for me. I needed to draw to the screen when another thread ends; but couldn't because the main thread has control of the screen. So:
(1) I created the global variable: boolean end1 = false;
The thread sets it to true when ending. That is picked up in the mainthread by "postDelayed" loop, where it is responded to.
(2) My thread contains:
void myThread() {
end1 = false;
new CountDownTimer(((60000, 1000) { // milliseconds for onFinish, onTick
public void onFinish()
{
// do stuff here once at end of time.
end1 = true; // signal that the thread has ended.
}
public void onTick(long millisUntilFinished)
{
// do stuff here repeatedly.
}
}.start();
}
(3) Fortunately, "postDelayed" runs in the main thread, so that's where in check the other thread once each second. When the other thread ends, this can begin whatever we want to do next.
Handler h1 = new Handler();
private void checkThread() {
h1.postDelayed(new Runnable() {
public void run() {
if (end1)
// resond to the second thread ending here.
else
h1.postDelayed(this, 1000);
}
}, 1000);
}
(4) Finally, start the whole thing running somewhere in your code by calling:
void startThread()
{
myThread();
checkThread();
}
I guess the easiest way is to use ThreadPoolExecutor
class.
- It has a queue and you can set how many threads should be working in parallel.
- It has nice callback methods:
Hook methods
This class provides protected overridable
beforeExecute(java.lang.Thread, java.lang.Runnable)
andafterExecute(java.lang.Runnable, java.lang.Throwable)
methods that are called before and after execution of each task. These can be used to manipulate the execution environment; for example, reinitializing ThreadLocals, gathering statistics, or adding log entries. Additionally, methodterminated()
can be overridden to perform any special processing that needs to be done once the Executor has fully terminated.
which is exactly what we need. We will override afterExecute()
to get callbacks after each thread is done and will override terminated()
to know when all threads are done.
So here is what you should do
Create an executor:
private ThreadPoolExecutor executor; private int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors(); private void initExecutor() { executor = new ThreadPoolExecutor( NUMBER_OF_CORES * 2, //core pool size NUMBER_OF_CORES * 2, //max pool size 60L, //keep aive time TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>() ) { @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); //Yet another thread is finished: informUiAboutProgress(executor.getCompletedTaskCount(), listOfUrisToProcess.size()); } } }; @Override protected void terminated() { super.terminated(); informUiThatWeAreDone(); } }
And start your threads:
private void startTheWork(){ for (Uri uri : listOfUrisToProcess) { executor.execute(new Runnable() { @Override public void run() { doSomeHeavyWork(uri); } }); } executor.shutdown(); //call it when you won't add jobs anymore }
Inside method informUiThatWeAreDone();
do whatever you need to do when all threads are done, for example, update UI.
NOTE: Don't forget about using synchronized
methods since you do your work in parallel and BE VERY CAUTIOUS if you decide to call synchronized
method from another synchronized
method! This often leads to deadlocks
Hope this helps!
You could also use SwingWorker, which has built-in property change support. See addPropertyChangeListener() or the get() method for a state change listener example.
Look at the Java documentation for the Thread class. You can check the thread's state. If you put the three threads in member variables, then all three threads can read each other's states.
You have to be a bit careful, though, because you can cause race conditions between the threads. Just try to avoid complicated logic based on the state of the other threads. Definitely avoid multiple threads writing to the same variables.
참고URL : https://stackoverflow.com/questions/702415/how-to-know-if-other-threads-have-finished
'Programming' 카테고리의 다른 글
data.frame의 각 행을 복제하고 각 행의 복제 수를 지정하십시오. (0) | 2020.07.12 |
---|---|
순간에 기간 추가 (moment.js) (0) | 2020.07.12 |
공유 객체에서 모든 심볼을 내보내는 방법은 무엇입니까? (0) | 2020.07.12 |
ASP.NET MVC 5 및 WEB API 2에서 oauth2 서버를 구현하는 방법 (0) | 2020.07.12 |
현재 파일의 전체 경로를 확장하여 Vim의 명령에 전달하려면 어떻게해야합니까? (0) | 2020.07.12 |