为什么ExecutorCompletionService不使用ExecutorService池

时间:2016-01-04 19:16:04

标签: java multithreading concurrency

由于某种原因,java.util.concurrent.ExecutorCompletionService未使用java.util.concurrent.ExecutorService线程池中的线程。这会影响ExecutorCompletionService.submit()方法调用的“阻塞”执行。请考虑以下代码:

package completionservicedemo1;

import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class CompletionServiceDemo1 {

    static final ExecutorService executor = Executors.newFixedThreadPool(10, new ThreadFactory() {

        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r);
            thread.setName("Executor-Thread");
            try {
                System.out.println("Thread going to sleep: "+Thread.currentThread().getName());
                thread.sleep(5000L);
                System.out.println("Thread awakened: "+Thread.currentThread().getName());
            } catch (InterruptedException ex) {
                System.out.println("InteruptedException: "+ex);
            }
            return thread;
        }
    });

    static final ExecutorCompletionService<String> completionService = new ExecutorCompletionService<>(executor);
    static byte val=1;

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        System.out.println("App start time: "+ new Date());

        completionService.submit(()->"String"+ ++val);
        System.out.println("All tasks submitted at: "+ new Date());

    }    
}

输出:

应用开始时间:2016年1月5日星期二00:20:27 IST 2016

线程进入睡眠状态:主

线程被唤醒:主要

所有任务提交于:2016年1月5日00:20:32 IST 2016

很明显,ExecutorCompletionStage没有使用ExecutorService池中的线程,因此completionService.submit(()->"String"+ ++val);会在延迟5秒后响应。

理想情况下,submit()方法应将传递的Callable实例任务提交到ExecutorService池以进行并发执行。但这显然不会发生,因为输出中的线程名称显示。

有人可以解释一下这里发生的事情吗?为什么不同时在ExecutorService线程池上计算Callable?为什么completionService.submit()阻塞(5s)?

2 个答案:

答案 0 :(得分:5)

  

为什么ExecutorCompletionService不使用ExecutorService池中的线程?

确实如此。见结束答案。

javadoc of newFixedThreadPool

  

使用提供的ThreadFactory在需要时创建新线程

换句话说,返回的ExecutorService个线程是根据需要懒惰地创建newThread的。

提交任务时

completionService.submit(()->"String"+ ++val);

没有Thread个实例可用于接受任务。因此,ExecutorService将使用newThread创建新主题。它在调用线程main中执行此操作。由于您的newThread已实现睡眠5秒,这正是它的作用。 sleep完成后,newThread将返回Thread实例,ExecutorService将启动并执行提交的

()->"String"+ ++val

请注意,您的任务仅连接Stringint值并返回结果。

将其更改为

Future<String> future = completionService.submit(() -> "String" + ++val + " Thread " + Thread.currentThread());
System.out.println("All tasks submitted at: " + new Date());
System.out.println("Future returned: " + future.get());

在返回的get上调用Future以等待其完成并看到有用的内容。

答案 1 :(得分:0)

阅读@Sotirios Delimanolis&#39;回复,我能够解决我的问题,并了解问题。我错误地搜索了将在ThreadFactory.newThread()内执行Callable而不是Callable.call()方法的工作线程名称。在解决这个案例后,一切都是连贯的:

package completionservicedemo1;

import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;

public class CompletionServiceDemo1 {

    static final ExecutorService executor = Executors.newFixedThreadPool(10, new ThreadFactory() {

        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r);
            thread.setName("Executor-Thread");
            try {
                System.out.println("Thread going to sleep: "+Thread.currentThread().getName());
                thread.sleep(1000L);
                System.out.println("Thread awakened: "+Thread.currentThread().getName());
            } catch (InterruptedException ex) {
                System.out.println("InteruptedException: "+ex);
            }
            return thread;
        }
    });

    static final ExecutorCompletionService<String> completionService = new ExecutorCompletionService<>(executor);
    static byte val=1;

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        System.out.println("App start time: "+ new Date());

        completionService.submit(()->{
            System.out.println("Thread executing the callable: "+Thread.currentThread().getName()+" "+new Date());
            Thread.sleep(10000L);
            System.out.println("Worker Thread came out of sleep: "+Thread.currentThread().getName()+" "+new Date());
            return "String"+ ++val;
        });
        System.out.println("All tasks submitted at: "+ new Date());

        System.out.println("main thread taking completed future at: "+new Date());

        //following would block on the BlockingQue as there is a 10s delay
        Future<String> resultingFuture = completionService.take(); 

        //following would not block since only completed Futures are placed on the BlockingQue (by QueueingFuture)
            System.out.println("result: "+resultingFuture.get()); 

        System.out.println("main thread got completed future result at: "+new Date());

    }    
}

输出:

应用开始时间:2016年1月5日星期二08:00:06

线程进入睡眠状态:主

线程被唤醒:主要

所有任务提交时间:2016年1月5日08:00:07 IST 2016

主线程完成未来:2016年1月5日08:00:07 IST 2016

线程执行callable:Executor-Thread Tue Jan 05 08:00:07 IST 2016

工人线程从睡眠中醒来:Executor-Thread Tue Jan 05 08:00:17 IST 2016

结果:String2

主线程已完成未来结果:Tue Jan 05 08:00:17 IST 2016