如何在Java中共享对象列表以进行并行处理?

时间:2016-05-31 07:23:38

标签: java multithreading parallel-processing

我有一个必须在多个线程之间共享的对象列表。

例如,我有5个离散对象和20个线程的池。 20个线程中的前5个将开始工作,其他线程处于WAIT状态。 5个线程将​​同时使用5个对象中的每一个。

如果任何线程完成,它应该释放该对象,以便第6个线程可以开始工作。

对于线程的并行处理,我认为我可以使用Executor池。但是如何在线程之间共享对象列表呢?

5 个答案:

答案 0 :(得分:2)

我认为你的线程模型错了。目前,您希望share在并行环境中始终存在错误。你应该做的是创建一个pipeline。为此,您有几种选择。

  1. 使用(阻塞/并发)队列在线程之间传递对象。在这种情况下,管道的每个阶段都有固定数量的工作线程,这些工作线程始终在运行并共享队列。一方面,你有producer个线程,当它们完成put()对象到队列,然后一个consumer线程take()对象并开始处理它。

  2. 使用threadpool作为(1)中的队列。您不必在共享队列上执行put(),而是submit()/execute()到共享或专用线程池,以将对象传递到管道的下一个阶段。这种方法的缺点是,当前阶段必须知道提交任务的确切池,以及知道如何创建要提交的runnable

  3. PS:在我的回答中,我假设Thread-6执行的操作与前5个线程不同。如果这个假设不正确 - 解决方案(1)仍然是正确的,并且是前进的方向。

答案 1 :(得分:1)

您可以定义要并行运行的线程数。例如,

ExecutorService executor = Executors.newFixedThreadPool(20);

然后你可以写一个for循环来处理对象列表。

for(Object obj: objList) {
    Runnable thread = new MyThreadImpl(obj);
    executor.execute(thread);
}

根据你的

,这应该完全正常

答案 2 :(得分:1)

在我看来,你在谈论Object pool pattern。对象池是包含指定数量对象的容器。当从池中取出一个对象时,它将在池中不可用,直到它被放回。

在以下情况下应使用池:

  • 使用相同对象的高频率
  • 对象非常大并且消耗大量内存
  • 对象需要很长时间进行初始化
  • 对象使用大量IO操作(Streams,Sockets,DB等)
  • 对象不是线程安全的

某些出版物不建议使用对象池,尤其是对于仅使用内存且不保留外部资源的对象。相关批评question

取决于你为什么需要这种模式。这是implementation in Java

答案 3 :(得分:0)

我怀疑JDK中是否有标准实现,但您可以根据您的要求构建自己的对象池,也可以查看库,例如https://commons.apache.org/proper/commons-pool/

答案 4 :(得分:0)

使用可重入锁

private static synchronized ReentrantLock getLock(Long id) {
    if (!locks.containsKey(id)) {
        locks.put(id, new ReentrantLock());
    }
    return locks.get(id);
}

private void lock(Long id) {
    ReentrantLock lock = getLock(id);
    lock.lock();
}

private void unlock(Long id) {
    ReentrantLock lock = getLock(id);
    if (lock.isHeldByCurrentThread()) {
        lock.unlock();
    }
}