是否可以将ForkJoinPool
配置为使用1个执行线程?
我正在执行在Random
内调用ForkJoinPool
的代码。每次运行时,我都会遇到不同的运行时行为,因此很难调查回归。
我希望代码库提供" debug"和"发布"模式。 "调试" mode将使用固定种子配置Random
,并使用单个执行线程配置ForkJoinPool
。 "释放" mode将使用系统提供的Random
种子并使用默认数量的ForkJoinPool
个线程。
我尝试使用1的并行度配置ForkJoinPool
,但它使用2个线程(main
和第二个工作线程)。有什么想法吗?
答案 0 :(得分:7)
所以,事实证明我错了。
配置ForkJoinPool
并将parallelism
设置为1时,只有一个线程执行任务。 main
线程在ForkJoin.get()
上被阻止。它实际上并没有执行任何任务。
也就是说,事实证明提供确定性行为真的很棘手。以下是我必须纠正的一些问题:
ForkJoinPool
正在使用不同的工作线程(具有不同的名称)执行任务。例如,如果主线程在调试断点上挂起,则工作线程将变为空闲并关闭。当我恢复执行时,ForkJoinThread
将启动一个具有不同名称的新工作线程。为了解决这个问题,我不得不provide a custom ForkJoinWorkerThreadFactory
implementation that returns null
if the ForkJoinPool
already has a live worker(这可以防止池创建多个工作者)。即使工作线程关闭并再次返回,我也确保我的代码返回相同的Random
实例。HashMap
或HashSet
)导致元素在每次运行时以不同的顺序获取随机数。我使用LinkedHashMap
和LinkedHashSet
。Enum.hashCode()
。我忘了这引起了什么问题但我通过自己计算hashCode()而不是依赖内置方法来纠正它。这是ForkJoinWorkerThreadFactory的示例实现:
class MyForkJoinWorkerThread extends ForkJoinWorkerThread
{
MyForkJoinWorkerThread(ForkJoinPool pool)
{
super(pool);
// Change thread name after ForkJoinPool.registerWorker() does the same
setName("DETERMINISTIC_WORKER");
}
}
ForkJoinWorkerThreadFactory factory = new ForkJoinWorkerThreadFactory()
{
private WeakReference<Thread> currentWorker = new WeakReference<>(null);
@Override
public synchronized ForkJoinWorkerThread newThread(ForkJoinPool pool)
{
// If the pool already has a live thread, wait for it to shut down.
Thread thread = currentWorker.get();
if (thread != null && thread.isAlive())
{
try
{
thread.join();
}
catch (InterruptedException e)
{
log.error("", e);
}
}
ForkJoinWorkerThread result = new MyForkJoinWorkerThread(pool);
currentWorker = new WeakReference<>(result);
return result;
}
};
答案 1 :(得分:0)
主线程始终是应用程序将创建的第一个线程。因此,当您使用ForkJoinPool
parallelism
创建1
时,您正在创建另一个帖子。实际上,应用程序中将有两个线程(因为您创建了pool
个线程)。
如果您只需要一个Main主题,则可以按顺序执行代码(而不是并行执行)。