[英]How to start thread when at least one is finished
我有 4 個線程。 每 x 秒打印給定字母 x 次。 任務是立即啟動 3 個線程,並在至少一個先前線程完成時啟動第 4 個線程。 我不知道如何通知最后一個線程在適當的時候運行。
CompletableFutures是以一種富有表現力的方式實現這一目標的現代方式。
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
CompletableFuture<Void> a = CompletableFuture.runAsync(() -> print("A"), executor);
CompletableFuture<Void> b = CompletableFuture.runAsync(() -> print("B"), executor);
CompletableFuture<Void> c = CompletableFuture.runAsync(() -> print("C"), executor);
CompletableFuture.anyOf(a, b, c).thenRunAsync(() -> print("D"), executor);
}
private static void print(String taskName) {
for (int i = 0; i < 10_000; ++i) {
System.out.println("Task " + taskName + ": " + i);
}
}
運行 A、B 和 C,然后當其中任何一個完成后,運行 D。
您可以通過刪除執行程序並僅使用 fork/join 池來進一步簡化它,但它在獨立示例中效果不佳,因為它們是守護線程; 該程序將在執行任何操作之前很快結束。
取決於你的任務是什么? 你關心工作嗎? 線程?
您總是可以通過創建具有三個線程的線程池並為其分配四個任務來“破解它”:
ExecutorService es = Executors.newFixedThreadPool(3);
es.execute(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("A");
try {Thread.sleep(100);} catch (InterruptedException e) {}
}
});
es.execute(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("B");
try {Thread.sleep(100);} catch (InterruptedException e) {}
}
});
es.execute(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("C");
try {Thread.sleep(100);} catch (InterruptedException e) {}
}
});
es.execute(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("D");
try {Thread.sleep(100);} catch (InterruptedException e) {}
}
});
或者自己創建線程(首先是 D 線程),並在每個 (ABC) 工作結束時詢問 D 是否正在運行,如果沒有,則啟動它。
有很多解決方案,復雜性大相徑庭,它們是否合適完全取決於您的上下文。
要使用信號量等待 3 個線程之一完成,在啟動第 4 個不同的線程之前,您可以將信號量初始化為0
。 在運行第 4 個線程之前,您獲得了信號量,但不能,因為它是0
。 當 3 個線程之一完成時,它釋放信號量,允許第 4 個線程運行。
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
public class Main {
public static void main(String[] args) throws InterruptedException {
Semaphore sem = new Semaphore(0);
char[] letters = {'a', 'b', 'c'};
List<Thread> threadList = new ArrayList<>();
for (int threadNum = 0; threadNum < 3; threadNum++) {
int finalThreadNum = threadNum;
Thread t = new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.print(letters[finalThreadNum]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
sem.release();
});
threadList.add(t);
t.start();
}
Thread lastThread = new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.print('d');
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
sem.acquire();
lastThread.start();
for (Thread t : threadList) {
t.join();
}
lastThread.join();
}
}
您可以使用Semaphore
。 前 3 個線程將獲得所有許可,當第一個線程釋放許可時,第 4 個線程將獲取並運行。
public static void main(String [] args) throws IOException {
Semaphore semaphore = new Semaphore(3, true);
Runnable a = new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
for (int i = 0; i < 50; i++) {
System.out.println("A");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
};
Runnable b = new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
for (int i = 0; i < 50; i++) {
System.out.println("B");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
};
Runnable c = new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
for (int i = 0; i < 50; i++) {
System.out.println("C");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
};
Runnable d = new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
System.out.println("D");
} catch (Exception e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
};
ExecutorService exec = Executors.newFixedThreadPool(5);
exec.execute(a);
exec.execute(b);
exec.execute(c);
exec.execute(d);
}
如果第 4 個線程的 semaphore.acquire() 發生在其他 3 個線程的獲取之前怎么辦...
您可以為此使用CountDownLatch
。 基於@Ryan 的回答:
public static void main(String [] args) throws IOException {
Semaphore semaphore = new Semaphore(3, true);
CountDownLatch okToStartTaskD = new CountDownLatch(3);
Runnable a = new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
okToStartTaskD.countDown();
...
}
...
}
};
Runnable b = new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
okToStartTaskD.countDown();
...
}
...
}
};
...
ExecutorService exec = Executors.newFixedThreadPool(5);
exec.execute(a);
exec.execute(b);
exec.execute(c);
try {
okToStartTaskD.await();
}
catch (InterruptedException ex) {
ex.printStackTrace();
...should never get here, but what if?...
}
exec.execute(d);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.