Java 使用并行流阻止所有其他线程

Java 使用并行流阻止所有其他线程,java,Java,我有一个小程序,它可以启动4个线程,每个线程的数量为偶数到20。 我只对其中一个线程执行了睡眠,但似乎所有其他线程都被阻塞,等待阻塞的线程恢复 为什么启用并行流处理会导致这种行为 public class Program { static int first; public static void main(String[] a) throws InterruptedException { new Program().runTask

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

您的问题是假设静态在启动后仍然对线程可用

创建第一个lambda时,第一个变量的值可能为零,但不久之后,几乎可以肯定,在第一次调用delay时,它的值为1

这就达到了您想要的效果-打印延迟为预期的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;
    }
}

您的问题是假设静态在启动后仍然对线程可用

创建第一个lambda时,第一个变量的值可能为零,但不久之后,几乎可以肯定,在第一次调用delay时,它的值为1

这就达到了您想要的效果-打印延迟为预期的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;
    }
}
您从不首先初始化,因此它从sun文档开始为0:

声明字段时并不总是需要赋值。 已声明但未初始化的字段将设置为 编译器的合理默认值。一般来说,这是默认的 将为零或null,具体取决于数据类型。依靠这些 然而,默认值通常被认为是糟糕的编程 风格

因此,当您执行first++时,它的值为1,因此所有其他线程都处于休眠状态。 将first初始化为1可以解决此问题,如下所示:

static int first = 1;
默认值 您从不首先初始化,因此它从sun文档开始为0:

声明字段时并不总是需要赋值。 已声明但未初始化的字段将设置为 编译器的合理默认值。一般来说,这是默认的 将为零或null,具体取决于数据类型。依靠这些 然而,默认值通常被认为是糟糕的编程 风格

因此,当您执行first++时,它的值为1,因此所有其他线程都处于休眠状态。 将first初始化为1可以解决此问题,如下所示:

static int first = 1;
默认值