java多线程中的CompletionService

在java编程的时候,可能我们会经常遇到多线程的处理问题

有些时候只需要创建子线程让其执行一些逻辑,但是不需要返回数据,那就可以用Thread或者Runnable来实现就行

而有些时候需要创建多个子线程去执行逻辑,并且执行完成后需要拿到返回数据,就可以使用Callable

当我们使用线程池去提交Callable线程任务就可以拿到线程执行返回的Future引用对象,如果不使用CompletionService,那么我们需要自己去创建一个Future的集合,遍历来取值,这样有个不好的地方,如果自己用集合去装Future,那么它的顺序就是根据任务提交的顺序获取子线程返回的值,如果第一个线程执行了10秒而后面的线程最多才执行1秒,那么用这种方式去获取第一个future对象的时候就会被阻塞10秒,若需要多个子线程执行并且特定的线程执行完成之后可以做其他业务,那么这种方式就不适合

如果使用CompletionService去提交任务,返回的Future对象会根据执行的时间将执行最快的子线程的结果最先返回

不使用CompletionService就相当于:
线程池 + Callable + 阻塞队列

使用CompletionService就相当于:
线程池 + CompletionService(Callable + 阻塞队列 + 时间优先返回)

下面是一个测试:

这里定义一个Callable:

package cn.lijie.thread;

import java.util.concurrent.Callable;

public class MyCallable implements Callable<String> {

    private int sleep;

    public MyCallable(int sleep) {
        this.sleep = sleep;
    }

    public String call() throws Exception {
        Thread.sleep(sleep);
        return Thread.currentThread().getName() + ":睡眠了" + sleep + "秒";
    }
}

如果不使用CompletionService:

package cn.lijie.thread;

import java.util.concurrent.*;

public class MainOne {

    public static void main(String[] args) throws Exception {

        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(200);

        //创建阻塞队列
        BlockingQueue> blockingQueue = new LinkedBlockingQueue>();

        for (int i = 10; i > 0; i--) {
            Future future = executorService.submit(new MyCallable(i * 500));
            blockingQueue.add(future);
        }
        for (int i = 1; i <= 10; i++) {
            Future take = blockingQueue.take();
            String res = take.get();
            System.out.println("MainOwo查看执行情况:" + res);
        }

        executorService.shutdown();

    }
}

执行的结果如下:

java多线程中的CompletionService_第1张图片

如果使用CompletionService:

package cn.lijie.thread;

import java.util.concurrent.*;

public class MainTwo {

    public static void main(String[] args) throws Exception {

        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(200);

        //创建CompletionService
        CompletionService completionService = new ExecutorCompletionService(executorService);

        for (int i = 10; i > 0; i--) {
            completionService.submit(new MyCallable(i * 500));
        }

        for (int i = 1; i <= 10; i++) {
            Future take = completionService.take();
            String res = take.get();
            System.out.println("MainTwo查看执行情况:" + res);
        }
        executorService.shutdown();

    }
}

执行结果如下:

java多线程中的CompletionService_第2张图片

可以通过上面的执行结果对比,使用了CompletionService 就会先获取到最快执行完成的子线程返回值,而不使用CompletionService就按照提交顺序阻塞获取

你可能感兴趣的:(Java,java,多线程,future,线程池)