如何在Java中共享用于并行处理的对象列表



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

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

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

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

我认为您的线程模型有误。当前您想要share,这在并行环境中总是错误的。相反,您应该创建一个pipeline。要做到这一点,你有几个选择。

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

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

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

在我看来,你在谈论对象池模式。对象池是包含指定数量的对象的容器。从池中提取对象时,在将其放回池之前,该对象在池中不可用。

池应用于以下情况:

  • 高频使用相同对象
  • 对象很大,占用大量内存
  • 对象需要大量时间进行初始化
  • 对象使用大量IO操作(流、套接字、DB等)
  • 对象不是线程安全的

一些出版物不建议使用对象池,尤其是对于只使用内存且不包含外部资源的对象。相关批评问题。

这取决于你为什么需要这种模式。下面是Java的实现。

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

ExecutorService executor = Executors.newFixedThreadPool(20);

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

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

根据你的,这应该可以很好地工作

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

使用Reentrant Locks

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();
}
}

最新更新