我有一个必须在多个线程之间共享的对象列表。
例如,我有一个5个离散对象和一个由20个线程组成的池。在20个线程中的前5个线程将开始工作,使其他线程处于WAIT状态。5个线程将同时使用5个对象中的每一个。
如果任何一个线程完成,它应该释放对象,以便第六个线程可以开始工作。
对于线程的并行处理,我认为我可以使用Executor池。但是如何在线程之间共享对象列表呢?
我认为您的线程模型有误。当前您想要share
,这在并行环境中总是错误的。相反,您应该创建一个pipeline
。要做到这一点,你有几个选择。
-
使用(阻塞/并发)队列在线程之间传递对象。在这种情况下,管道的每个阶段都有固定数量的工作线程,这些线程始终在运行并共享队列。在一侧,您有
producer
线程,当它们完成put()
时,将对象放入队列,然后其中一个consumer
线程take()
将对象放入并开始处理。 -
使用
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();
}
}