我有一堆runnables,我想通过线程池执行。但是,每个runnable也会将一些结果写入某个文件。所以现在,runnable的界面很简单:
class MyRunnable implements Runnable {
...
MyRunnable(BufferedWriter writer, Task t) {
this.writer = writer;
this.task = t;
}
public void run() {
...
this.writer.write(SOME_DATA);
}
}
但是,我想要的是将一个BufferedWriter(换句话说,一个输出文件)与Executor池中的每个线程相关联。但是,我使用.execute
调用ExecutorService
函数,如下所示:
BufferedWriter[] writers = initialize to 20 BufferedWriters;
ExecutorService executor = Executors.newFixedThreadPool(20);
for (Task t : tasks) {
MyRunnable runnable = new MyRunnable(WHAT SHOULD GO HERE?, t)
executor.execute(runnable);
}
我不知道执行程序将为运行给定任务分配哪个线程,所以我不知道我应该向runnable提供哪个BufferedWriter。如何确保ExecutorService管理的每个线程都与一个对象相关联(在本例中为BufferedWriter)?
答案 0 :(得分:3)
此处有一个名为ThreadLocal
的课程。
e.g。
ThreadLocal<Type> t = new ThreadLocal<>() {
@Override protected Type initialValue() {
return new Type(Thread.currentThread.getName());
}
每次新线程尝试访问Type
时,这将延迟初始化t
。
我上次使用这个类只是在一个类中,以确定某个机器运行最多的线程数。 (答案通常是“核心数量”,但我想确保虚拟核心驱动此数字而不是物理核心)。所以我写了一个任务,其中每个线程只是发送了一个AtomicInteger
计数器。但是所有的线程都在争夺一个计数器,这会产生大量的开销来处理线程争用,所以我创建了一个threadlocal计数器,所以线程可以垃圾邮件自己的计数器而不受其他线程的干扰。
它的用例有点模糊,因为大多数好的多线程设计都避免这种情况,但当然有时候会这样。
答案 1 :(得分:2)
...我想要将一个BufferedWriter(换句话说,一个输出文件)与Executor池中的每个线程相关联......
@ djechlin关于ThreadLocal
的答案很好,但问题是当线程完成最后一个任务时,你无法访问BufferedWriter
到close()
。
可以在这里看到另一种答案:
在其中,我建议创建自己的BlockingQueue
任务,并为每个线程分配一个任务,让这些线程从队列中获取任务。所以线程运行方法就像:
private final BlockingQueue<MyRunnable> queue = new ArrayBlockingQueue<>();
// if you want to shutdown your threads with a boolean
private volatile boolean shutdown;
...
// threads running in the `ExecutorService` will be doing this run() method
public void run() {
// this allows them to maintain state, in this case your writer
BufferedWriter writer = ...;
while (!shutdown && !Thread.currentThread.isInterrupted()) {
// they get their tasks from your own queue
MyRunnable runnable = queue.take();
// if you are using a poison pill but you'll have to add X of them
if (runnable == STOP_OBJECT) {
break;
}
runnable.run();
}
writer.close();
}
在线程完成时告诉线程在这里有点棘手。你可以在队列中添加一个“毒丸”对象,但是你必须在线程运行时向队列中添加相同数量的对象。