1.Executor接口实现线程池管理

从JDK 5开始,Java中增加了Executor接口及其子类,允许使用线程池的技术来管理线程并发问题。Executor接口提供了ExecutorService子接口,通过该子接口可以方便的进行线程池的管理。

通过Executor接口接口实现线程池的管理主要步骤如下:

  • ① 创建并实现Runnable接口或者Callable接口的实现类,同时重写run()方法或者call()方法。
  • ② 创建Runnable接口或者Callable接口的实现类对象。
  • ③ 使用Executors线程执行器类创建线程池。
  • ④ 使用ExecutorService执行器服务类的submit()方法将Runnable接口或者Callable接口的实现类对象提交到线程池进行管理。
  • ⑤ 线程池执行完成后,可以使用shutdown()方法进行关闭线程池。
import java.util.concurrent.*;

class MyThread implements Callable<Object> {
    @Override
    public Object call() throws Exception {
        int i=0;
        while(i<5){
        	i++;
            System.out.println(Thread.currentThread().getName()+"的call()方法正在运行");
        }
        return i;
    }
}

public class test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyThread myThread = new MyThread();
        //可扩展的线程池
        ExecutorService executor = Executors.newCachedThreadPool();
        Future<Object> submit1 = executor.submit(myThread);
        Future<Object> submit2 = executor.submit(myThread);

        executor.shutdown();
        System.out.println("线程1返回的结果是:"+submit1.get());
        System.out.println("线程1返回的结果是:"+submit2.get());
    }
}

alt

线程池是通过Executors的newCachedThreadPool()方法创建的,Executors是Java中增加线程执行器的工作类,提供了4种不同的方式来创建用于不同需求的线程池。。

Executors创建线程池的方法

方法申明 功能描述
ExecutorService newCachedThreadPool() 创建一个可扩展的线程池的执行器,这个线程池适用于启动许多多短期任务的应用程序
ExecutorService newFixedThreadPool(int nThreads) 创建一个固定线程数量线程池的执行器,这种线程执行器可以很好的控制多线程任务,也不会导致由于响应过多导致的程序崩溃
ExecutorService newSingleThreadExecutor() 在特殊需求下创建一个只执行一个任务的单个线程
ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 创建一个定长的线程池,只支持定时及周期性任务执行

参考链接:https://www.yii666.com/article/710328.html

2.CompletableFuture类实现线程池管理

在使用Callable接口实现多线程时,会用到FutureTask类对线程执行管理和获取,由于该类在获取结果时是通过阻塞或者轮询的方式,违背了多线程编程的初衷且耗费过多资源。 在jdk 8中,增加了FutureTask存在的不足进行了改进,增加了一个强大的函数是异步编程辅助类CompletableFuture,该类同时实现了Future接口和CompletionStage接口,并对Future进行了强大的扩展,简化异步编程的复杂性。

在使用CompletableFuture类在进行线程管理时,通常会使用4个静态方法来为一段一步执行的代码创建CompletableFuture对象。

方法申明 功能描述
CompletableFuture runAsync(Runnable runnable) 以Runnable函数式接口类型为参数,并使用ForkJoinPool.commonPool()作为它的线程池执行异步代码获取CompletableFuture计算结果为空的对象
CompletableFuture runAsync(Runnable runnable,Executor executor) 以Runnable函数式接口类型为参数,并传入指定的线程池执行器executor来获取CompletableFuture计算结果为空的对象
CompletableFuture supplyAsync(Supplier supplier) 以Supplier函数式接口类型为参数,并使用ForkJoinPool.commonPool()作为它的线程池执行异步代码获取CompletableFuture计算结果为非空的对象
CompletableFuture supplyAsync(Supplier supplier,Executor executor) 以Supplier函数式接口类型为参数,并传入指定的线程池执行器executor来获取CompletableFuture计算结果非空的对象
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建第二个线程,从1加到5
        CompletableFuture<Integer> integerCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
            int sum = 0, i = 0;
            while (i++ < 5) {
                sum = sum + i;
                System.out.println(Thread.currentThread().getName() + "线程正在执行...i:" + i);
            }
            return sum;
        });
        //创建第二个线程,从6加到10

        CompletableFuture<Integer> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
            int sum = 0, i = 5;
            while (i++ < 10) {
                sum = sum + i;
                System.out.println(Thread.currentThread().getName() + "线程正在执行...i:" + i);
            }
            return sum;
        });

        CompletableFuture<Integer> result = integerCompletableFuture1.thenCombine(integerCompletableFuture2, (integer, integer2) -> integer + integer2);
        System.out.println("从1加到10的结果是:"+result.get());
    }
}

alt

注: 使用Executor接口实现线程池管理可以更好地控制线程池的大小和任务队列的长度,但是需要手动创建和管理线程池。而使用CompletableFuture类实现线程池管理可以更加方便地编写异步代码,但是需要注意内存泄漏问题。