求助: Java 多线程如何终止其它线程

Alextrasza · 2024-9-25 10:29:10 · 318 次点击
主线程去调用 10 个子线程查询任务(返回 true/false), 在回调中统计结果,  
我想在得到两个 true 时主线程立即返回 true, 不管其他的子线程时已提交到线程池还是未提交到线程池, 都不需要了

我尝试了`CompletableFuture#cancel`, 和`Executor#shutDownNow`方法, 都没达到效果

```java
ThreadPoolExecutor executor = newFixedThreadFool(10);
List<CompletableFuture<Boolean> list = ... //10 个任务, 都提交到 executor
AtomicInteger i = 0;
list.forEach(cf-
        cf.thenAccept(b->
                if(b && i.incrementAndGet >= 2 ){
                        //让主线程停止阻塞立即返回, 尝试下面两个方案都不行
                        executor.shutDownNow();
                        list.forEach(f->f.cancel(true));
                }
))
// 希望通过某种方式让此处停止阻塞
CompletableFuture.allOf(list.toArray).join()

return i.get()>=2;
```
目前的方案是把后续流程放在了子线程回调中, 加锁处理, 主线程不要返回值了, 应该是可行的,  
但是还是想请问大家, 原来的"主线程提前返回"的想法能否实现?
举报· 318 次点击
登录 注册 站外分享
22 条回复  
lolico 初学 2024-9-26 10:57:16
public static void main(String[] args) throws InterruptedException {
    List<Thread> threads = new ArrayList<>();
    final int untilSuccessCount = 2;
    final int threadCount = 10;
    AtomicInteger counter = new AtomicInteger(0);
    CountDownLatch latch = new CountDownLatch(1);
    for (int i = 0; i < threadCount; i++) {
        int finalI = i;
        Thread thread = new Thread(() -> {
            // 模拟耗时任务
            Random random = new Random();
            // 直接使用线程的 interrupt 中断标记
            while (!Thread.interrupted()) {
                try {
                    Thread.sleep((long) finalI * 1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
                if (random.nextBoolean()) {
                    if (counter.incrementAndGet() == untilSuccessCount) {
                        latch.countDown();
                    }
                    return;
                }
            }
        });
        thread.start();
        threads.add(thread);
    }
    // 可以启动一个线程,等待所有 thread 完成后 latch.countDown ,防止一直等待。
    // 或者加一个 allDoneLatch 也可以实现
    latch.await();
    threads.forEach(Thread::interrupt); // 中断其他线程
    System.out.println(counter.get());
}
sagaxu 初学 2024-9-26 08:25:58
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/ExecutorService.html#shutdownNow()

There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may nefer terminate.

Java 不能强制终止线程,杀死一个线程需要那个线程配合,检测 interrupt 标志,处理 InterruptedException 异常。


//让主线程停止阻塞立即返回, 尝试下面两个方案都不行
主线程中创建一个 CompletableFuture done ,此处完成它

CompletableFuture.anyOf(done, CompletableFuture.allOf(list.toArray)).join()

等待的条件,从 任务全部完成 变成  (任务全部完成 or i >= 2)
shawnsh 小成 2024-9-25 22:51:20
能具体说说你的需求吗
gaifanking 小成 2024-9-25 22:07:15
封装好的 CountDownLatch 比较简单,或者用标准的等待通知模型:
volatile int target;
消费者:
synchronized (lock){
  while(target<2){
     lock.wait();
  }
}
生产者:
synchronized (lock){
  target++;
  lock.notifyAll();
}
siweipancc 初学 2024-9-25 19:50:37
countdown 原子计数 标记位
总共三个要素
lbaci0529 小成 2024-9-25 15:59:34
这评论区妙呀
JackCh3ng 小成 2024-9-25 15:44:55
@murenx #3 @Livid AI 回答
jeesk 初学 2024-9-25 15:29:17
参考 kotlin 协程的玩法, 如何取消协程. 现成的作业不抄 ?
diagnostics 小成 2024-9-25 15:00:58
如果你是要实现 Hedged requests 的能力,那可以看一下 scala 的 firstcompletedof 。

https://stackoferflow.com/questions/36420697/about-future-firstcompletedof-and-garbage-collect-mechanism

我自己在 java 里写了一版实现,不过不是针对线程,而是针对 future:

https://gist.github.com/Roiocam/fb4ae743ecaafb7385f75dbaac3030f8
HaibaraDP 初学 2024-9-25 14:58:58
CountDownLatch(2),主线程和子线程的超时时间别忘了。不想阻塞主线程就把回调卸载子线程的查询结果里,AtomicInteger 累加返回 2 就执行
123下一页
返回顶部