Java 使用newSingleThreadExecutor消除ExecutorService中的争用条件
为了理解赛车,我编写了以下程序:Java 使用newSingleThreadExecutor消除ExecutorService中的争用条件,java,executorservice,synchronized,Java,Executorservice,Synchronized,为了理解赛车,我编写了以下程序: import java.util.concurrent.*; class RaceCount { static int count = 0; public static void main(String [] args) { ExecutorService executor = Executors.newSingleThreadExecutor(); for (int i = 0; i
import java.util.concurrent.*;
class RaceCount
{
static int count = 0;
public static void main(String [] args)
{
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 1000; i++)
{
executor.submit(new Callable<String>() {
public String call() throws Exception {
count++; return "Incremented";
}
});
}
executor.shutdown();
System.out.println(count);
}
}
但是,结果仍然不到1000。如果我使用newFixedThreadExecutor(1000)而不是newSingleThreadExecutor,那么即使call()方法的前缀没有synchronized关键字,我也会得到预期的1000。因此,我的问题是:
1.如何在newSingleThreadExecutor的情况下同步线程?
2.当使用newFixedThreadExecutor时,为什么不需要同步 您的问题不是由于比赛条件造成的。之所以发生这种情况,仅仅是因为
executor.shutdown()
在返回之前没有等待完全关闭
这是来自java.util.concurrent.ExecutorService.shutdown()
的javadocs:
此方法不会等待以前提交的任务完成执行。使用此选项可以完成此操作 换句话说,
System.out.println(count)
在某些任务运行之前运行(尽管它必须在提交所有任务之后运行)
我对您的代码做了一个小改动,以使这一事实变得明显:
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 1000; i++) {
int e = i;
executor.submit(new Callable<String>() {
public String call() throws Exception {
System.out.println("Executing " + e);
count++;
return "Incremented";
}
});
}
executor.shutdown();
System.out.println("Count: " + count);
}
关于关机的部分只是解决方案的一半。 “public synchronized String call()”这将同步调用,以便只有一个线程可以同时执行一个实例的调用,但是使用“executor.submit(new Callable()”,您有1000个调用实例。因此实际上没有同步。
您可以在循环外部将其更改为“Callable call=new Callable()…”,在循环内部更改为“executor.submit(call);”,这样您就有了一个同步的调用实例。或者从“int i”更改为“AtomicInteger i”,从++i更改为i.incrementAndGet();请参见
executor.waitemination()
!
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 1000; i++) {
int e = i;
executor.submit(new Callable<String>() {
public String call() throws Exception {
System.out.println("Executing " + e);
count++;
return "Incremented";
}
});
}
executor.shutdown();
System.out.println("Count: " + count);
}
...
Executing 835
Executing 836
Executing 837
Count: 837 <----- Printed before all tasks are run
Executing 838
Executing 839
Executing 840
Executing 841
...
executor.shutdown();
executor.awaitTermination(3, TimeUnit.SECONDS); //Pick an appropriate timeout value
System.out.println("Count: " + count);