Java 当池结束时

Java 当池结束时,java,java-8,parallel-processing,java-stream,Java,Java 8,Parallel Processing,Java Stream,我试图找出所有ForkJoinPool线程何时完成了任务。 我编写了这个测试应用程序(我使用System.out,因为它只是一个快速测试应用程序,并且没有错误检查/处理): 公共类TestForkJoinPoolEnd{ private static final Queue=new LinkedList(); 专用静态最终整数最大值=5000; 专用静态最终整数速度_UP=100; 公共静态void main(字符串[]args){ ForkJoinPool customThreadPool=新

我试图找出所有ForkJoinPool线程何时完成了任务。 我编写了这个测试应用程序(我使用System.out,因为它只是一个快速测试应用程序,并且没有错误检查/处理):

公共类TestForkJoinPoolEnd{
private static final Queue=new LinkedList();
专用静态最终整数最大值=5000;
专用静态最终整数速度_UP=100;
公共静态void main(字符串[]args){
ForkJoinPool customThreadPool=新的ForkJoinPool(12);
customThreadPool.submit(
()->makeList()
.parallelStream()
.forEach(TestForkJoinPoolEnd::process));
排队(“启动了硬件池”);
int计数器=最大_大小+1;
而(!customThreadPool.isTerminating()){
字符串s=dequeue();
如果(s!=null){
系统输出打印项次;
计数器--;
}
试一试{
时间单位。毫秒。睡眠(1);
}捕捉(中断异常e){
}
}
System.out.println(“计数器=”+计数器);
System.out.println(“Isquisite=“+customThreadPool.Isquisite()+”isTerminating”+
“=”+customThreadPool.isTerminating()+“isTerminated=”
+customThreadPool.IsShutton()+“IsShutton=“+customThreadPool.IsShutton());
}
静态列表生成列表(){
返回流。生成(()->makeString())
.限制(最大尺寸)
.collect(Collectors.toList());
}
静态字符串makeString(){
int leftLimit=97;//字母“a”
int rightLimit=122;//字母“z”
int targetStringLength=10;
随机=新随机();
StringBuilder缓冲区=新StringBuilder(targetStringLength);
对于(int i=0;i
这段代码被卡住了,永远不会结束。如果我将while循环的条件更改为
!customThreadPool.isquisite()
它在计数器和队列大小设置为1时终止循环


我应该使用什么来确定线程何时完成?

一个
执行器服务
不会仅仅因为一个作业(及其子作业)完成而自行终止。线程池背后的全部思想是可重用的

因此,它将仅在应用程序对其调用
shutdown()
时终止

您可以使用
isquisite()
确定是否没有挂起的作业,只有当所有提交的作业都属于您的特定任务时,挂起的作业才有效。使用
submit
返回的future来检查实际作业的完成情况要干净得多

在任何一种情况下,排队任务的完成状态都不会说明您正在轮询的队列。在了解提交结束时,您仍然需要检查队列中是否有挂起的元素

此外,建议使用线程安全的
BlockingQueue
实现,而不是用
synchronized
块装饰
LinkedList
。再加上一些需要清理的内容,代码将如下所示:

public class TestForkJoinPoolEnd {
    private static final BlockingQueue<String> QUEUE = new LinkedBlockingQueue<>();
    private static final int MAX_SIZE = 5000;
    private static final int SPEED_UP = 100;

    public static void main(String[] args) {
        ForkJoinPool customThreadPool = new ForkJoinPool(12);
        ForkJoinTask<?> future = customThreadPool.submit(
            () -> makeList()
                    .parallelStream()
                    .forEach(TestForkJoinPoolEnd::process));
        QUEUE.offer("Theard pool started up");

        int counter = MAX_SIZE + 1;
        while (!future.isDone()) try {
            String s = QUEUE.poll(1, TimeUnit.MILLISECONDS);
            if (s != null) {
                System.out.println(s);
                counter--;
            }
        } catch (InterruptedException e) {}

        for(;;) {
            String s = QUEUE.poll();
            if (s == null) break;
            System.out.println(s);
            counter--;
        }
        System.out.println("counter = " + counter);
        System.out.println("isQuiescent = " + customThreadPool.isQuiescent()     + " isTerminating " +
                "= " + customThreadPool.isTerminating() + " isTerminated = "
                + customThreadPool.isTerminated() + " isShutdown =" +     customThreadPool.isShutdown());

        customThreadPool.shutdown();
    }

    static List<String> makeList() {
        return IntStream.range(0, MAX_SIZE)
            .mapToObj(i -> makeString())
            .collect(Collectors.toList());
    }

    static String makeString() {
        int targetStringLength = 10;
        Random random = new Random();
        StringBuilder buffer = new StringBuilder(targetStringLength);
        for (int i = 0; i < targetStringLength; i++) {
            int randomLimitedInt = random.nextInt('z' - 'a' + 1) + 'a';
            buffer.append((char) randomLimitedInt);
        }
        return buffer.toString();
    }

    static int toSeed(String s) {
        return s.chars().sum() / SPEED_UP;
    }

    static void process(String s) {
        long start = System.nanoTime();
        try {
            TimeUnit.MILLISECONDS.sleep(toSeed(s));
        } catch (InterruptedException e) {

        }
        long end = System.nanoTime();
        QUEUE.offer(s + " slept for " + (end - start)/1000000 + " milliseconds");
    }
}
但逻辑没有改变。在
future.isDone()
返回
true
后,我们必须重新检查队列中的挂起元素。我们只保证不会有新的物品到达,而不是队列已经空了

作为旁注,
makeString()
方法可以进一步改进以

static String makeString() {
    int targetStringLength = 10;
    ThreadLocalRandom random = ThreadLocalRandom.current();
    StringBuilder buffer = new StringBuilder(targetStringLength);
    for (int i = 0; i < targetStringLength; i++) {
        int randomLimitedInt = random.nextInt('a', 'z' + 1);
        buffer.append((char)randomLimitedInt);
    }
    return buffer.toString();
}

ExecutorService
不会因为一个作业(及其子作业)完成而自行终止。线程池背后的全部思想是可重用的

因此,它将仅在应用程序对其调用
shutdown()
时终止

您可以使用
isquisite()
确定是否没有挂起的作业,只有当所有提交的作业都属于您的特定任务时,挂起的作业才有效。使用
submit
返回的future来检查实际作业的完成情况要干净得多

在任何一种情况下,排队任务的完成状态都不会说明您正在轮询的队列。在了解提交结束时,您仍然需要检查队列中是否有挂起的元素

此外,建议使用线程安全的
BlockingQueue
实现,而不是用
synchronized
块装饰
LinkedList
。再加上一些需要清理的内容,代码将如下所示:

public class TestForkJoinPoolEnd {
    private static final BlockingQueue<String> QUEUE = new LinkedBlockingQueue<>();
    private static final int MAX_SIZE = 5000;
    private static final int SPEED_UP = 100;

    public static void main(String[] args) {
        ForkJoinPool customThreadPool = new ForkJoinPool(12);
        ForkJoinTask<?> future = customThreadPool.submit(
            () -> makeList()
                    .parallelStream()
                    .forEach(TestForkJoinPoolEnd::process));
        QUEUE.offer("Theard pool started up");

        int counter = MAX_SIZE + 1;
        while (!future.isDone()) try {
            String s = QUEUE.poll(1, TimeUnit.MILLISECONDS);
            if (s != null) {
                System.out.println(s);
                counter--;
            }
        } catch (InterruptedException e) {}

        for(;;) {
            String s = QUEUE.poll();
            if (s == null) break;
            System.out.println(s);
            counter--;
        }
        System.out.println("counter = " + counter);
        System.out.println("isQuiescent = " + customThreadPool.isQuiescent()     + " isTerminating " +
                "= " + customThreadPool.isTerminating() + " isTerminated = "
                + customThreadPool.isTerminated() + " isShutdown =" +     customThreadPool.isShutdown());

        customThreadPool.shutdown();
    }

    static List<String> makeList() {
        return IntStream.range(0, MAX_SIZE)
            .mapToObj(i -> makeString())
            .collect(Collectors.toList());
    }

    static String makeString() {
        int targetStringLength = 10;
        Random random = new Random();
        StringBuilder buffer = new StringBuilder(targetStringLength);
        for (int i = 0; i < targetStringLength; i++) {
            int randomLimitedInt = random.nextInt('z' - 'a' + 1) + 'a';
            buffer.append((char) randomLimitedInt);
        }
        return buffer.toString();
    }

    static int toSeed(String s) {
        return s.chars().sum() / SPEED_UP;
    }

    static void process(String s) {
        long start = System.nanoTime();
        try {
            TimeUnit.MILLISECONDS.sleep(toSeed(s));
        } catch (InterruptedException e) {

        }
        long end = System.nanoTime();
        QUEUE.offer(s + " slept for " + (end - start)/1000000 + " milliseconds");
    }
}
但逻辑没有改变。在
future.isDone()
返回
true
后,我们必须重新检查队列中的挂起元素。我们只保证不会有新的物品到达,而不是队列已经空了

作为旁注,
makeString()
方法
static String makeString() {
    int targetStringLength = 10;
    ThreadLocalRandom random = ThreadLocalRandom.current();
    StringBuilder buffer = new StringBuilder(targetStringLength);
    for (int i = 0; i < targetStringLength; i++) {
        int randomLimitedInt = random.nextInt('a', 'z' + 1);
        buffer.append((char)randomLimitedInt);
    }
    return buffer.toString();
}
static String makeString() {
    int targetStringLength = 10;
    return ThreadLocalRandom.current()
        .ints(targetStringLength, 'a', 'z'+1)
        .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
        .toString();
}