gpt4 book ai didi

Java:ExecutorService线程与CountDownLatch同步导致死锁?

转载 作者:行者123 更新时间:2023-11-30 04:48:54 30 4
gpt4 key购买 nike

我写了一个生命游戏来练习编程。生成器有 3 种不同的实现。第一:一个主线程 + N 个子线程,第二:SwingWorker + N 个子线程,第三:SwingWorker + ExecutorService。N 是可用处理器或用户定义的数量。前两个实现运行良好,具有一个和多个线程。ExecutorServise 的实现在一个线程上运行良好,但在多个线程上锁定。我尝试了一切,但无法得到解决方案。

这里是精细工作实现的代码(第二个):

    package example.generator;

import javax.swing.SwingWorker;

/**
* AbstractGenerator implementation 2: SwingWorker + sub threads.
*
* @author Dima
*/
public final class WorldGenerator2 extends AbstractGenerator {


/**
* Constructor.
* @param gamePanel The game panel
*/
public WorldGenerator2() {
super();
}




/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startGenerationProcess()
*/
@Override
protected void startGenerationProcess() {
final SwingWorker<Void, Void> worker = this.createWorker();
worker.execute();
}




/**
* Creates a swing worker for the generation process.
* @return The swing worker
*/
private SwingWorker<Void, Void> createWorker() {
return new SwingWorker<Void, Void>() {

@Override
protected Void doInBackground() throws InterruptedException {
WorldGenerator2.this.generationProcessing();
return null;
}
};
}





/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startFirstStep()
*/
@Override
public void startFirstStep() throws InterruptedException {
this.getQueue().addAll(this.getLivingCells());
for (int i = 0; i < this.getCoresToUse(); i++) {
final Thread thread = new Thread() {
@Override
public void run() {
WorldGenerator2.this.fistStepProcessing();
}
};
thread.start();
thread.join();
}
}




/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startSecondStep()
*/
@Override
protected void startSecondStep() throws InterruptedException {
this.getQueue().addAll(this.getCellsToCheck());
for (int i = 0; i < this.getCoresToUse(); i++) {
final Thread thread = new Thread() {

@Override
public void run() {
WorldGenerator2.this.secondStepProcessing();
}
};
thread.start();
thread.join();
}
}

}

这是执行程序服务无法正常工作的实现的代码:

    package example.generator;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.SwingWorker;

/**
* AbstractGenerator implementation 3: SwingWorker + ExecutorService.
*
* @author Dima
*/
public final class WorldGenerator3 extends AbstractGenerator {


private CountDownLatch countDownLatch;
private ExecutorService executor;


/**
* Constructor.
* @param gamePanel The game panel
*/
public WorldGenerator3() {
super();
}




/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startGenerationProcess()
*/
@Override
protected void startGenerationProcess() {
this.executor = Executors.newFixedThreadPool(this.getCoresToUse());
final SwingWorker<Void, Void> worker = this.createWorker();
worker.execute();
}




/**
* Creates a swing worker for the generation process.
* @return The swing worker
*/
private SwingWorker<Void, Void> createWorker() {
return new SwingWorker<Void, Void>() {

@Override
protected Void doInBackground() throws InterruptedException {
WorldGenerator3.this.generationProcessing();
return null;
}
};
}




/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startFirstStep()
*/
@Override
public void startFirstStep() throws InterruptedException {
this.getQueue().addAll(this.getLivingCells());
this.countDownLatch = new CountDownLatch(this.getCoresToUse());
for (int i = 0; i < this.getCoresToUse(); i++) {
this.executor.execute(new Runnable() {
@Override
public void run() {
WorldGenerator3.this.fistStepProcessing();
WorldGenerator3.this.countDownLatch.countDown();
}
});
}
this.countDownLatch.await();

}




/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startSecondStep()
*/
@Override
protected void startSecondStep() throws InterruptedException {
this.getQueue().addAll(this.getCellsToCheck());
this.countDownLatch = new CountDownLatch(this.getCoresToUse());
for (int i = 0; i < this.getCoresToUse(); i++) {
this.executor.execute(new Runnable() {
@Override
public void run() {
WorldGenerator3.this.secondStepProcessing();
WorldGenerator3.this.countDownLatch.countDown();
}
});
}
this.countDownLatch.await();

}
}

在这里您可以下载我的应用程序示例,其中包含一个小型启动器。它仅在控制台上打印迭代的结果:Link

<小时/>

现在我的代码如下所示:

/* (non-Javadoc)
* @see main.generator.AbstractGenerator#startFirstStep()
*/
@Override
public void startFirstStep() throws InterruptedException {

this.getQueue().addAll(this.getLivingCells());

final ArrayList<Callable<Void>> list = new ArrayList<Callable<Void>>(this.getCoresToUse());

for (int i = 0; i < this.getCoresToUse(); i++) {

list.add(new Callable<Void>() {

@Override
public Void call() throws Exception {
WorldGenerator3.this.fistStepProcessing();
return null;
}
}
);
}

this.executor.invokeAll(list);
}

但是这里又出现了同样的问题。如果我用一个核心(线程)运行它,就没有问题。如果我将核心数设置为多个,它就会锁定。在我的第一个问题中,有一个示例的链接,您可以运行该示例(在 Eclipse 中)。也许我忽略了前面代码中的一些内容。

最佳答案

我发现您对执行程序设施的使用有点奇怪......

即这个想法是让 Executor 拥有一个线程池,线程池的大小通常与 CPU 支持的核心数量有关。然后,您向执行器提交任意数量的并行任务,让它决定何时以及在池中的哪个可用线程上执行什么。

至于 CountDownLatch...为什么不使用 ExecutorService.invokeAll ?该方法将阻塞,直到所有提交的任务完成或达到超时。所以它会代表你计算剩下的工作。或者CompletionService如果您想在任务结果可用时立即使用它,即不等待所有任务先完成,那么它“将新异步任务的生成与已完成任务结果的消耗分离”。

类似于

    private static final int WORKER_THREAD_COUNT_DEFAULT = Runtime.getRuntime().availableProcessors() * 2;

ExecutorService executor = Executors.newFixedThreadPool(WORKER_THREAD_COUNT);

// your tasks may or may not return result so consuming invokeAll return value may not be necessary in your case
List<Future<T>> futuresResult = executor.invokeAll(tasksToRunInParallel, EXECUTE_TIMEOUT,
TimeUnit.SECONDS);

关于Java:ExecutorService线程与CountDownLatch同步导致死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10283224/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com