使用Parallel Stream阻止所有其他线程

时间:2015-05-05 12:37:53

标签: java

我有一个小程序,它启动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;
        }
    }

2 个答案:

答案 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;

默认值

enter image description here