此問題的完整代碼可在此處獲得: https ://github.com/NACHC-CAD/thread-tool
下面顯示的代碼似乎運行完成,但從未逃脫此處顯示的 while 回圈。
while (this.active.size() > 0) {
// System.out.println("here");
}
如果我取消注釋// System.out.println("here");它會運行到完成。如果我添加一秒鐘的睡眠,它也會運行完成。
更大的問題是,如果我嘗試在實際應用程式中使用此代碼,代碼會運行一段時間然后似乎死鎖(即代碼只是停止運行)。
我需要做什么來解決這個問題?
package org.nachc.tools.threadtool;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.nachc.tools.threadtool.runnableiter.ThreadToolUser;
import org.nachc.tools.threadtool.worker.ThreadToolWorker;
import org.nachc.tools.threadtool.worker.ThreadToolWorkerRunnable;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ThreadRunner {
private int numberOfThreadsPerWorker;
private int numberOfRunnablesPerWorker;
private int numberOfWorkers;
private ThreadToolUser runnableIter;
private List<ThreadToolWorker> active = new ArrayList<ThreadToolWorker>();
private Object lock = new Object();
private ThreadPoolExecutor executor;
public ThreadRunner(int numberOfThreadsPerWorker, int numberOfRunnablesPerWorker, int numberOfWorkers, ThreadToolUser runnableIter) {
this.numberOfThreadsPerWorker = numberOfThreadsPerWorker;
this.numberOfRunnablesPerWorker = numberOfRunnablesPerWorker;
this.numberOfWorkers = numberOfWorkers;
this.runnableIter = runnableIter;
this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(numberOfWorkers);
}
public void exec() {
synchronized (lock) {
addWorkers();
}
while (this.active.size() > 0) {
// System.out.println("here");
}
log.info("SHUTTING DOWN----------------");
executor.shutdown();
try {
executor.awaitTermination(1000, TimeUnit.HOURS);
} catch (Exception exp) {
throw (new RuntimeException(exp));
}
}
private void addWorkers() {
log.info("start addWorkers");
while (runnableIter.hasNext() && active.size() < numberOfWorkers) {
ThreadToolWorker worker = getNextWorker();
if (worker == null) {
break;
} else {
this.active.add(worker);
}
}
log.info("done addWorkers");
}
private ThreadToolWorker getNextWorker() {
synchronized (lock) {
log.info("start next worker");
if (runnableIter.hasNext() == false) {
return null;
}
List<Runnable> runnableList = new ArrayList<Runnable>();
while (runnableList.size() < numberOfRunnablesPerWorker && runnableIter.hasNext()) {
runnableList.add(runnableIter.getNext());
}
ThreadToolWorker worker = new ThreadToolWorker(runnableList, numberOfThreadsPerWorker, this);
ThreadToolWorkerRunnable runnable = new ThreadToolWorkerRunnable(worker);
this.executor.execute(runnable);
log.info("done next worker");
return worker;
}
}
public void done(ThreadToolWorker worker) {
synchronized (lock) {
log.info("start done");
this.active.remove(worker);
if (active.size() > 0) {
addWorkers();
}
log.info("done done");
}
}
public void logActive() {
synchronized (lock) {
log.info("------------");
log.info("active: " active.size());
log.info("waiting: " runnableIter.waiting());
log.info("------------");
}
}
}
uj5u.com熱心網友回復:
您的回圈訪問this.active.size()沒有任何同步。如果查看共享變數的執行緒不使用與其他執行緒的某種同步形式,Java 的記憶體可見性規則不保證查看共享變數的執行緒何時(如果有的話)會看到其他執行緒所做的更改。
如果要輪詢串列的狀態,請active考慮執行以下操作:
while (true) {
synchronized(lock) {
if (this.active.size() <= 0) break;
}
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
該sleep()呼叫使其他執行緒有機會運行。如果沒有睡眠,運行此回圈的執行緒將使用 100% 的 CPU,這可能不利于您的應用程式的性能。
但是有比輪詢更好的選擇。您可以這樣做以等到active串列變空。
synchronized(lock) {
while (this.active.size() > 0) {
lock.wait();
}
}
該wait()呼叫暫時釋放lock,然后它等待另一個執行緒notify()獲得鎖,最后,它在回傳之前重新鎖定鎖:
public void done(ThreadToolWorker worker) {
synchronized (lock) {
log.info("start done");
this.active.remove(worker);
if (active.size() > 0) {
addWorkers();
}
else {
lock.notifyAll();
}
log.info("done done");
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/469140.html
