过多的短暂线程是开销极大的,所以用线程池吧,每个线程结束后,不会立马消亡,而是入池等待下一个服务

想要停止一个线程需要两步,一步是知道哪个线程去处理,一步是线程本身要有停止的能力

Callables and Futures

Callable 就是 Runnable 的升级版,是一个泛型,接受返回类型,执行后也会有个返回值。但是直接获取这个返回值 Callable 是做不到的,所以要用 Future 包一下,通过 Future 来获取

Callable<Integer> task = . . .;
 
var futureTask = new FutureTask<Integer>(task); 
var t = new Thread(futureTask); // it's a Runnable t.start(); . . .
 
Integer result = futureTask.get(); // it's a Future

FutureTask 实现了 FutureRunnable,所以满足 “is-a” 条件

可能是历史遗留因素,Thread 只接受 Runnable,所以需要 Future 包一下

带参数的 Runnable

可以让 Runnable 包含几个成员变量作为参数

暂时不理解为什么不能用 BiConsumer

Executors (Thread Pools)

三个 factory methods,来产生缓存式,定长式,单线式的池。其中单线的用来测试性能,可以比较使用并发到底性能有没有改变 (想想也是,一旦并发就会有阻塞,有时候反而会更慢)

submit

在使用上,前面的可以忘记掉,submit 任何 able,然后返回一个 Future

Future<T> submit(Callable<T> task) 
Future<?> submit(Runnable task) 
Future<T> submit(Runnable task, T result)

shut down

shutdown 会停止接受新的 task,然后在 task 都完成后,关掉线程池

shutdownNow 在此基础上,停止尚未开始的 task,然后完成之后关掉

scheduled

除了立马执行的普通线程池,还有类似的定时线程和线程池

Controlling Groups of Tasks


总的来说,线程池的使用流程为:

  1. 工厂方法创建线程池
  2. submit Callable 或者 Runnable 给线程池,并接受好 Future
  3. 等待 Future 返回值
  4. 关闭线程池