一 . 概述
我们创建线程的代价是相当大的,线程池就是一个减少线程创建代价的事物.核心就是完成线程创建的任务.
当然当我们将线程的创建工作都交给了线程池,那么线程池就拥有了线程的控制权.
三 .线程池的分类
在JUC之中将线程池分成四类:
我们看一下类的结构.
public class PoolTest { public static void main(String[] args) { //线程池 //1 带缓冲区的线程池 Executor ex1 = Executors.newCachedThreadPool(); //创建单一线程的线程池 Executor ex2 = Executors.newSingleThreadExecutor(); //创建固定数量的线程池 Executor ex3 = Executors.newFixedThreadPool(5); //创建带调度的线程池 Executor ex4 = Executors.newScheduledThreadPool(3); } }
上面介绍了我们最为常见的四种线程池.
三 . 带缓冲的线程池
解析: 当下线程池创建的时候会创建一定数量的缓存线程,当需要线程的时候直接从线程池中获取线程.
当线程池中的线程不足时,直接创建新的线程,当使用完,设置线程的终止时间倒计时,如果到倒计时还没用处,直接终结线程.
因此,我们能看到带缓冲的线程池是我们比较常用的一种.
四. 单一线程的线程池
很简单,就是这个线程池只维护一个线程,当过多的线程任务到来的时候,会排队接收线程任务.
五 .固定线程数的线程池
这个也十分的简单,就是线程池的线程数量是固定的,当过多的线程到来的时候,会排队等待.
六 . 任务调度的线程池
线程池可以按照指定的延迟进行线程的调度,比如每一秒调度一个线程.
七.线程池的基本使用
我们使用带缓冲区的线程池为例:
@Test public void test() throws Exception { // 创建线程池 ExecutorService service = Executors.newCachedThreadPool(); // 提交线程任务 for (int x = 0; x < 3; x++) { service.submit(new Runnable() { @Override public void run() { System.out.println("我们提交的是Runnable接口,没有返回值"); } }); } List<Future<Integer>> resultList = new ArrayList<>(); for (int x = 0; x < 3; x++) { int temp = x; Future<Integer> result = service.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { return temp; } }); resultList.add(result); } //关闭线程池 service.shutdown(); // 主线程休眠1秒 Thread.sleep(1000); // 拿出结果 resultList.stream().forEach(e -> { try { System.out.println(e.get()); } catch (InterruptedException | ExecutionException e1) { e1.printStackTrace(); } }); }
在这里我们需要注意的就是,我们使用线程池的时候,可以传递Runnable接口的线程任务,此时是没有返回值的/
也可以传入Callable接口的线程任务.此时我们是可以获取返回值的.
注意: Future接口的返回值的获取的阻塞式的.