我的任务将受益于线程池设计模式(许多小任务要并行执行)。我最初从头开始实现了一个天真的线程池,其中n个Runnables都从同一个ConcurrentLinkedQueue
拉出工作单元,直到队列为空,然后终止。然后我决定“嘿,让我们尝试Java中的Executor,因为它可能比我天真设计的系统更好地测试和更可靠。”问题:在我的实现中,每个线程持续到队列为空,使用while (!queue.isEmpty())
,并获得自己的非线程安全对象实例,让我们称之为SlowObject foo
,这很耗时构建。尝试传递进入Runnable
池的所有Executor
时间效率低的对象的实例失败,因为它不是线程安全的。为每个SlowObject
创建Runnable
的新实例是不可取的,因为它们构建成本很高。
有没有办法说“我们使用了多少个线程?让我们为每个线程创建一个SlowObject
,然后让Runnables检测我们所在的线程并查找要使用的正确对象? “这听起来很脆弱且容易发生故障 - 但不确定我应该考虑哪种设计模式。
答案 0 :(得分:4)
最好使用资源池。使用这样的东西:
public class SlowObjectPool {
private static final int POOL_SIZE = 10;
private BlockingQueue<SlowObject> slowObjectQueue = new ArrayBlockingQueue(POOL_SIZE);
public SlowObjectPool() {
for (int i = 0; i < POOL_SIZE; i++) {
slowObjectQueue.put(new SlowObject());
}
}
public SlowObject take() throws InterruptedException {
return slowObjectQueue.take();
}
public void release(SlowObject slowObject) {
// TODO You may want to log a warning if this is false
slowObjectQueue.offer(slowObject);
}
}
您可能也希望将其设为单身人士。然后在你的runnables:
public class MyRunnable implements Runnable {
private SlowObjectPool pool;
public MyRunnable(SlowObjectPool pool) {
this.pool = pool;
}
@Override
public void run() {
// The next line blocks until a SlowObject is available
SomeObject someObject = null;
try {
someObject = pool.take()
// Do something with someObject
} catch (InterruptedException ex) {
// Thread is being ended, allow to end
} finally {
if (someObject != null)
pool.release(someObject);
}
}
}
这将在首次创建池时一次性创建对象,而不是动态创建它们,这样就不会有任何runnable必须等待创建SomeObject
个实例。
答案 1 :(得分:3)
Java提供了ThreadLocal变量的概念 您可以在Runnable之内使用它。
public class MyJob implements Runnable {
private static final ThreadLocal < SlowObject > threadLocal =
new ThreadLocal < SlowObject > () {
@Override protected SlowObject initialValue() {
// construct and return your SlowObject
}
};
public void run() {
// work with threadLocal.get()
}
}
因此,对于运行Runnable的每个线程,只创建一个SlowObject类的实例。