我有一个小程序,它启动4个线程,每个线程计数偶数到20。 我只在一个线程执行上休眠,但似乎所有其他线程都被阻塞,等待阻塞的线程恢复。
为什么启用并行流处理会导致此类行为?
public class Program {
static int first;
public static void main(String[] a) throws InterruptedException {
new Program().runTasks();
}
private void runTasks() throws InterruptedException {
int value = 20;
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> numberOfEvens(value));
first++;
executorService.execute(() -> numberOfEvens(value));
executorService.execute(() -> numberOfEvens(value));
executorService.execute(() -> numberOfEvens(value));
executorService.shutdown();
}
private void numberOfEvens(int val) {
System.out.println(IntStream.range(1, val).parallel().filter(this::isEven).count());
}
private void delay(int d) {
try {
Thread.sleep(d);
} catch (InterruptedException ex) {
// Do Nothing
}
}
private boolean isEven(int n) {
if (first == 1)
delay(1000);
return n % 2 == 0;
}
}
答案 0 :(得分:0)
您的问题是假设启动后线程仍然可以使用static
。
当您创建第一个lambda 时,first
变量的值可能为零,但很快就会有值1
,并且几乎可以肯定在第一次调用时delay
发生者。
这可以达到你想要的效果 - 按预期打印延迟 20次:
public static class Program {
public static void main(String[] a) throws InterruptedException {
new Program().runTasks();
}
private void runTasks() throws InterruptedException {
int value = 20;
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> numberOfEvens(value, true));
executorService.execute(() -> numberOfEvens(value, false));
executorService.execute(() -> numberOfEvens(value, false));
executorService.execute(() -> numberOfEvens(value, false));
executorService.execute(() -> numberOfEvens(value, false));
executorService.execute(() -> numberOfEvens(value, false));
executorService.execute(() -> numberOfEvens(value, false));
executorService.execute(() -> numberOfEvens(value, false));
executorService.execute(() -> numberOfEvens(value, false));
executorService.execute(() -> numberOfEvens(value, false));
executorService.execute(() -> numberOfEvens(value, false));
executorService.execute(() -> numberOfEvens(value, false));
executorService.execute(() -> numberOfEvens(value, false));
executorService.shutdown();
}
private void numberOfEvens(int val, boolean first) {
System.out.println(IntStream.range(1, val).parallel().filter(n -> isEven(n, first)).count());
}
private void delay(int d) {
try {
System.out.println("Delaying");
Thread.sleep(d);
} catch (InterruptedException ex) {
// Do Nothing
}
}
private boolean isEven(int n, boolean first) {
if (first) {
delay(1000);
}
return n % 2 == 0;
}
}
答案 1 :(得分:-1)
您永远不会初始化 ,因此从sun doc开始为0:
声明字段时并不总是需要指定值。 声明但未初始化的字段将设置为a 编译器合理默认。一般来说,这是默认的 将零或为null,具体取决于数据类型。依靠这样的 但是,默认值通常被认为是错误的编程 风格。
因此,当您执行first++
时,它的值为 1 ,因此所有其他线程都会休眠。
首先初始化为1应解决问题,如下所示:
static int first = 1;