Java中的“简单”线程池

3
我需要一个简单的对象来容纳我的工作线程,并且我不希望它限制线程的数量,也不希望它保持线程的生命周期长于必要时间。但是我确实需要一个类似于ExecutorService.shutdown();的方法(等待所有活动线程完成但不接受新线程)。
所以也许线程池不是我需要的,我希望得到正确的指引。(因为它们意味着保持线程的生命周期)
进一步说明:
每个线程都是一个文件上传,我有另一个进程来修改文件,但它会等待文件没有任何上传。通过加入每个线程,锁定该进程。 (每个线程在创建时将自己添加到特定文件的列表中,因此我只加入上传特定文件的线程)。
2个回答

6
一种实现你所需的方法是使用一个返回上传完成的File对象的Future和一个Callable。然后将这个Future传递给另一个Callable,检查Future.isDone()并旋转直到它返回true,然后进行文件处理。你的用例不是唯一的,非常适合java.util.concurrent 包功能
一个有趣的类是ExecutorCompletionService ,它可以等待结果然后进行附加计算,正好符合你的需求。
一个CompletionService,它使用提供的Executor来执行任务。此类安排提交的任务在完成后放置在可使用take访问的队列上。该类足够轻便,适用于处理任务组时的瞬态使用。 用法示例:假设您有一组解决某个问题的求解器,每个求解器返回某种类型Result的值,并且希望并发运行它们,在返回非空值的每个结果中处理它们的结果,使用某些方法use(Result r)。您可以编写如下内容:
   void solve(Executor e, Collection<Callable<Result>> solvers)
              throws InterruptedException, ExecutionException 
   {
       CompletionService<Result> ecs = new ExecutorCompletionService<Result>(e);
       for (Callable<Result> s : solvers) { ecs.submit(s); }
       int n = solvers.size();
       for (int i = 0; i < n; ++i) 
       {
           Result r = ecs.take().get();
           if (r != null) { use(r); }
       }
   }

不要使用无界的ExecutorService

几乎从不需要允许无限制的线程池,因为如果线程数量失控,它们实际上会限制应用程序的性能。

您的领域受到磁盘或网络I/O(或两者)的限制,因此小型线程池就足够了。您不想尝试使用每个连接一个线程来读取数百或数千个传入连接。

如果您正在接收多个并发上传,则解决方案的一部分是调查java.niopackage并阅读有关非阻塞I/O的信息。


0

你不想重复使用线程有什么原因吗?在我看来,最简单的方法是使用ExecutorService,让它重复利用线程。


每个线程都是一个文件的上传,我有另一个进程来修改文件,但它等待文件没有任何上传。通过加入每个线程,来锁定该进程。因此,当它们保持活动状态时,会锁定该进程。(每个线程在创建时将自己添加到特定文件的列表中,因此我只join()上传特定文件的线程) - Bg1987
2
你正在混淆两个概念:线程和任务。任务是“上传这个文件”,线程是用于完成任务的可重复使用资源。任务(上传的Runnable)可以在不调用线程的join()方法的情况下向“其他进程”发出完成信号。那么,“其他进程”如何接收这些信号呢? - Spike Gronim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接