【问题标题】:ThreadPoolExecutor - Specifying Which Thread Handles a Given TaskThreadPoolExecutor - 指定哪个线程处理给定任务
【发布时间】:2011-08-12 16:42:56
【问题描述】:

有没有一种好方法来实现一个执行策略,该策略根据某种识别方案确定哪个线程将处理给定任务?或者这甚至是一个好方法?

我需要处理 1 多个文件,我将以交错的块的形式接收这些文件。当块到达时,我想完成处理该块的任务。问题是我没有使处理代码线程安全的奢侈,所以一旦池中的线程处理了文件中的一个块,我需要同一个线程来处理该文件的其余部分。我不在乎一个线程是否同时处理多个文件,但我不能让池中的多个线程同时处理同一个文件。

“Java 并发实践”一书指出,您可以使用执行策略来确定“任务将在哪个线程中执行?”,但我不知道如何。

谢谢

【问题讨论】:

    标签: java multithreading parallel-processing threadpool task


    【解决方案1】:

    好吧,您可以编写自己的ThreadPoolExecutor - 但一般来说没有办法这样做。线程池的全部意义在于您只需向它投入工作,而不关心哪个线程获得哪个任务。在这种情况下,听起来您需要自己管理线程,并保留一个地图,说明哪个线程正在处理哪个文件。

    您知道文件何时完成吗?否则,您可能会遇到不断增长的地图的问题...

    【讨论】:

    • 您可以重用大部分 ThreadPoolExecutor 代码,只需在 execute() 前面添加一个过滤器 - 但我同意您的模式与 ThreadPoolExecutor 的预期用途并不匹配。
    • Jon 的解决方案很容易实现。您仍应使用线程池,但每个具有单个线程 (Executors.newSingleThreadExecutor()) 的池都与一个文件相关联。当一个块到达时,你只需调用 map.get(fileName(chunk)).execute(new TaskChunk(chunk))。如果你想限制线程的数量,你也可以为每个线程关联很多文件名。
    • 我确实知道何时收到文件的最后一组字节......我的印象是,将任务提交与执行分离是理想的,我引用的书中的陈述给了我印象是 ThreadPoolExecutor 做了很多工作,我只需要实现策略部分;如果我能够使处理代码线程安全,这也会给我更多的灵活性。我最初考虑了toto描述的方式,可能会采取这种方法。
    • 您可以通过将映射和线程池包装在其他对象 (MyExecutor) 中并调用 myExecutor.execute(new TaskChunk(chunk)); 来解耦策略。然后,您还需要一个 TaskChunk.getFileName() 方法,以便 execute() 知道要使用哪个线程。
    【解决方案2】:

    一个好主意可能是每个文件一个线程:

    HashMap<String, MyThreadImplementer> fileToThreadMap...
    
    class MyThreadImplementer implements Runnable {
        int maxNumParts;
        private List<FileChunk> chunkList...
        private List<FileChunk> doneChunks...
    
        public MyThreadImplementer(int maxNumberOfParts) {
            maxNumParts=maxNumberOfParts;
        }
    
        public void run() {
            while( doneChunks.size() < maxNumParts ) {
               Thread.sleep(...)
                if ( !chunkList.isEmpty() ) {
                    process each chunk in list and mvoe to done chunks
                }
            }
        }
    }
    

    但您需要注意不要处理 1000 个文件,从而创建 1000 个线程。

    【讨论】:

      【解决方案3】:

      您说您“没有使处理代码线程安全的奢侈”,但这并不意味着您需要将文件映射到特定线程。这只是意味着您无法开始处理文件中的下一个块,直到该文件中的最后一个块完成处理。

      利用 java.util.concurrent,您可以在主线程中维护一个 Map&lt;String, LinkedBlockingQueue&lt;FileChunk&gt;&gt;(假设文件名作为键),并在块进入时将每个块分配给相应文件的队列。然后有一个 @987654322 @阻塞每个队列。

      这样,一次只有一个线程会处理任何给定的文件。而且你不需要直接搞乱线程或维护多个线程池。

      【讨论】:

        猜你喜欢
        • 2018-08-27
        • 1970-01-01
        • 1970-01-01
        • 2017-08-03
        • 2013-08-29
        • 1970-01-01
        • 2010-11-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多