一、定义
1.作用
线程池:提供了一个级程队列,队列中保存着所有等特状态的线程。避免了创建与销象额外开销,提高了响应的速度。
2.体系结构
package java.util.concurrent.Executor:负责线程使用与调度的根接口
----》ExecutorService 子接口:线程池主要接口,内部方法基本满足线程池调度
--------》ThreadPoolExecutor:线程池的实现类
--------》ScheduledExecutorService 子接口:负责线程调度
3.工具类Executors
(1)创建固定大小的线程池
ExecutorService pool=Executors.newFixedThreadPool(10);
(2)创建缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量
ExecutorService pool2=Executors.newCachedThreadPool();
(3)创建单个线程池,线程池只有一个线程
ExecutorService pool3=Executors.newSingleThreadExecutor();
(4)创建固定大小线程池,可以延迟或者定时地执行任务
ExecutorService pool4=Executors.newScheduledThreadPool(5);
二、使用线程池实例
1.步骤
(1)创建线程池
(2)向线程池提交任务
(3)关闭线程池
2.提交实现Runnable接口的线程
(1)提交单个任务
package thread.threadpool;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class TestThreadPool {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//1.创建线程池
//(1)创建固定大小的线程池
// Executor
// ScheduledExecutorService
ExecutorService pool=Executors.newFixedThreadPool(10);
//(2)创建缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量
// ExecutorService pool2=Executors.newCachedThreadPool();
//(3)创建单个线程池,线程池只有一个线程
// ExecutorService pool3=Executors.newSingleThreadExecutor();
//(4)创建固定大小线程池,可以延迟或者定时地执行任务
// ExecutorService pool4=Executors.newScheduledThreadPool(5);
//2.为线程池分配任务
//2.1 提交实现Runnable接口的实例
ThreadPoolDemo threadPoolDemo=new ThreadPoolDemo();
//(1)提交单个任务
pool.submit(threadPoolDemo);
//3.关闭线程池
pool.shutdown();
}
}
class ThreadPoolDemo implements Runnable{
private int i=0;
@Override
public void run() {
while (i<=10){
System.out.println(Thread.currentThread().getName()+" : "+ ++i);
}
}
}
结果:
pool-1-thread-1 : 1
pool-1-thread-1 : 2
pool-1-thread-1 : 3
pool-1-thread-1 : 4
pool-1-thread-1 : 5
pool-1-thread-1 : 6
pool-1-thread-1 : 7
pool-1-thread-1 : 8
pool-1-thread-1 : 9
pool-1-thread-1 : 10
pool-1-thread-1 : 11
(2)提交多个任务
package thread.threadpool;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class TestThreadPool {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//1.创建线程池
//(1)创建固定大小的线程池
// Executor
// ScheduledExecutorService
ExecutorService pool=Executors.newFixedThreadPool(5);
//(2)创建缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量
// ExecutorService pool2=Executors.newCachedThreadPool();
//(3)创建单个线程池,线程池只有一个线程
// ExecutorService pool3=Executors.newSingleThreadExecutor();
//(4)创建固定大小线程池,可以延迟或者定时地执行任务
// ExecutorService pool4=Executors.newScheduledThreadPool(5);
//2.为线程池分配任务
//2.1 提交实现Runnable接口的实例
ThreadPoolDemo threadPoolDemo=new ThreadPoolDemo();
//(1)提交单个任务
// pool.submit(threadPoolDemo);
//(2)提交20个任务
for (int i = 0; i < 10; i++) {
pool.submit(threadPoolDemo);
}
//3.关闭线程池
pool.shutdown();
}
}
class ThreadPoolDemo implements Runnable{
private int i=0;
@Override
public void run() {
while (i<=10){
System.out.println(Thread.currentThread().getName()+" : "+ ++i);
}
}
}
结果:尽管提交了10个任务,但是线程池最多开了5个线程去执行
pool-1-thread-2 : 2
pool-1-thread-3 : 3
pool-1-thread-1 : 1
pool-1-thread-5 : 6
pool-1-thread-3 : 7
pool-1-thread-4 : 5
pool-1-thread-2 : 4
pool-1-thread-4 : 11
pool-1-thread-3 : 10
pool-1-thread-5 : 9
pool-1-thread-1 : 8
3.提交实现calable接口的线程
(1)提交单个任务
package thread.threadpool;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class TestThreadPool {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//1.创建线程池
//(1)创建固定大小的线程池
// Executor
// ScheduledExecutorService
ExecutorService pool=Executors.newFixedThreadPool(5);
//(2)创建缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量
// ExecutorService pool2=Executors.newCachedThreadPool();
//(3)创建单个线程池,线程池只有一个线程
// ExecutorService pool3=Executors.newSingleThreadExecutor();
//(4)创建固定大小线程池,可以延迟或者定时地执行任务
// ExecutorService pool4=Executors.newScheduledThreadPool(5);
//2.为线程池分配任务
//2.1 提交实现Runnable接口的实例
ThreadPoolDemo threadPoolDemo=new ThreadPoolDemo();
//(1)提交单个任务
// pool.submit(threadPoolDemo);
//(2)提交20个任务
// for (int i = 0; i < 10; i++) {
// pool.submit(threadPoolDemo);
// }
//2.2 提交实现Callable接口的实例
//(1)提交单个Callable任务
Future<Integer> future= pool.submit(new Callable<Integer>(){
@Override
public Integer call() throws Exception {
int sum=0;
for (int i = 0; i <= 100; i++) {
sum+=i;
}
return sum;
}
});
System.out.println(future.get());
//3.关闭线程池
pool.shutdown();
}
}
class ThreadPoolDemo implements Runnable{
private int i=0;
@Override
public void run() {
while (i<=10){
System.out.println(Thread.currentThread().getName()+" : "+ ++i);
}
}
}
结果:
5050
(2)提交多个任务
package thread.threadpool;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class TestThreadPool {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//1.创建线程池
//(1)创建固定大小的线程池
// Executor
// ScheduledExecutorService
ExecutorService pool=Executors.newFixedThreadPool(5);
//(2)创建缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量
// ExecutorService pool2=Executors.newCachedThreadPool();
//(3)创建单个线程池,线程池只有一个线程
// ExecutorService pool3=Executors.newSingleThreadExecutor();
//(4)创建固定大小线程池,可以延迟或者定时地执行任务
// ExecutorService pool4=Executors.newScheduledThreadPool(5);
//2.为线程池分配任务
//2.1 提交实现Runnable接口的实例
ThreadPoolDemo threadPoolDemo=new ThreadPoolDemo();
//(1)提交单个任务
// pool.submit(threadPoolDemo);
//(2)提交20个任务
// for (int i = 0; i < 10; i++) {
// pool.submit(threadPoolDemo);
// }
//2.2 提交实现Callable接口的实例
//(1)提交单个Callable任务
// Future<Integer> future= pool.submit(new Callable<Integer>(){
// @Override
// public Integer call() throws Exception {
// int sum=0;
// for (int i = 0; i <= 100; i++) {
// sum+=i;
// }
// return sum;
// }
// });
// System.out.println(future.get());
//(2)提交20个任务
List<Future<Integer>> list=new ArrayList<>();
for (int i = 0; i < 10; i++) {
Future<Integer> future= pool.submit(new Callable<Integer>(){
@Override
public Integer call() throws Exception {
int sum=0;
for (int i = 0; i <= 100; i++) {
sum+=i;
}
return sum;
}
});
list.add(future);
}
for (Future<Integer> future : list) {
System.out.println(future.get());
}
//3.关闭线程池
pool.shutdown();
}
}
class ThreadPoolDemo implements Runnable{
private int i=0;
@Override
public void run() {
while (i<=10){
System.out.println(Thread.currentThread().getName()+" : "+ ++i);
}
}
}
结果:
5050
5050
5050
5050
5050
5050
5050
5050
5050
5050
三、线程池实现类解析
1.ExecutorService接口方法
(1)作用:
定义一个线程池的时候,往往都是使用这个接口:
//1.创建线程池
//(1)创建固定大小的线程池
// Executor
// ScheduledExecutorService
ExecutorService pool=Executors.newFixedThreadPool(5);
//(2)创建缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量
// ExecutorService pool2=Executors.newCachedThreadPool();
//(3)创建单个线程池,线程池只有一个线程
// ExecutorService pool3=Executors.newSingleThreadExecutor();
//(4)创建固定大小线程池,可以延迟或者定时地执行任务
// ExecutorService pool4=Executors.newScheduledThreadPool(5);
(2)接口中常用方法以及解释
public interface ExecutorService extends Executor {
//关闭线程池,已提交的任务继续执行,不接受继续提交新任务
void shutdown();
//关闭线程池,尝试停止正在执行的所有任务,不接受继续提交新任务
//它和前面的方法相比,加了一个单词“now”,所以它会去停止当前正在进行的任务
List<Runnable> shutdownNow();
//线程池是否已关闭
boolean isShutdown();
//如果调用了 shutdown()或shutdownNow()方法后,所有任务结束了,那么返回true
//这个方法必须在调用shutdown或shutdownNow方法之后调用才会返回true
boolean isTerminated();
//等待所有任务完成,并设置超时时间
//我们这么理解,实际应用中是,先调用shutdown或shutdownNow
//然后再调这个方法等待所有的线程真正地完成,返回值意味着有没有超时
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
//提交一个Callable任务
<T> Future<T> submit(Callable<T> task);
//提交一个Runnable任务,第二个参数将会放到Future中,作为返回值,
//因为Runnable的run 方法本身并不返回任何东西
<T> Future<T> submit(Runnable task, T result);
//提交一个Runnable任务
Future<?> submit(Runnable task);
//执行所有任务,返回 Future类型的一个list
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;
//也是执行所有任务,但是这里设置了超时时间
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)
throws InterruptedException;
//只有其中的一个任务结束了,就可以返回,返回执行完的那个任务的结果
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
//同上一个方法,只有其中的一个任务结束了,就可以返回,返回执行完的那个任务的结果,
//不过这个带超时,超过指定的时间,抛出TimeoutException 异常
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
2.ThreadPoolExecutor
ThreadPoolExecutor是JDK中的线程池实现,这个类实现了一个线程池需要的各个方法,它实现了任务提交、线程管理、监控等等方法。
(1)构造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
(2)参数解释
- corePoolSize:核心线程数。
- maximumPoolSize:最大线程数,线程池允许创建的最大线程数。
- workQueue:任务队列,BlockingQueue接口的某个实现(常使用ArrayBlockingQueue和LinkedBlockingQueue)。
- keepAliveTime:空闲线程的保活时间,如果某线程的空闲时间超过这个值都没有任务给它做,那么可以被关闭了。注意这个值并不会对所有线程起作用,如果线程池中的线程数少于等于核心线程数corePoolSize,那么这些线程不会因为空闲太长时间而被关闭,当然,也可以通过调用allowCoreThreadTimeOut(true)使核心线程数内的线程也可以被回收。
- threadFactory:用于生成线程,一般我们可以用默认的就可以了。通常,我们可以通过它将我们的线程的名字设置得比较可读一些,如Message-Thread-1,Message-Thread-2类似这样。
- handler:当线程池已经满了,但是又有新的任务提交的时候,该采取什么策略由这个来指定。有几种方式可供选择,像抛出异常、直接拒绝然后返回等,也可以自己实现相应的接口实现自己的逻辑。
(3)流程
四、线程池的4种拒绝策略
1.拒绝时机
线程池会在以下两种情况下会拒绝新提交的任务
当我们调用 shutdown 等方法关闭线程池的时候,如果此时继续向线程池提交任务,就会被拒绝
当任务队列(workQueue)已满,而且线程达到最大线程数(maximumPoolSize),如果再增加任务,也会被拒绝
2.拒绝策略
2.1 核心接口
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
2.2 内建实现
2.2.1 CallerRunsPolicy
java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy
当有新任务提交后,如果线程池没被关闭且没有能力执行,则把这个任务交于提交任务的线程执行,也就是谁提交任务,谁就负责执行任务。这样做主要有两点好处。
第一点新提交的任务不会被丢弃,这样也就不会造成业务损失。
第二点好处是,由于谁提交任务谁就要负责执行任务,这样提交任务的线程就得负责执行任务,而执行任务又是比较耗时的,在这段期间,提交任务的线程被占用,也就不会再提交新的任务,减缓了任务提交的速度,相当于是一个负反馈。在此期间,线程池中的线程也可以充分利用这段时间来执行掉一部分任务,腾出一定的空间,相当于是给了线程池一定的缓冲期。
2.2.2 AbortPolicy
java.util.concurrent.ThreadPoolExecutor.AbortPolicy
拒绝策略在拒绝任务时,会直接抛出一个类型为 RejectedExecutionException 的 RuntimeException,让你感知到任务被拒绝了,于是你便可以根据业务逻辑选择重试或者放弃提交等策略。
2.2.3 DiscardPolicy
java.util.concurrent.ThreadPoolExecutor.DiscardPolicy
当新任务被提交后直接被丢弃掉,也不会给你任何的通知,相对而言存在一定的风险,因为我们提交的时候根本不知道这个任务会被丢弃,可能造成数据丢失。
2.2.4 DiscardOldestPolicy
java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy
如果线程池没被关闭且没有能力执行,则会丢弃任务队列中的头结点,通常是存活时间最长的任务,这种策略与第二种不同之处在于它丢弃的不是最新提交的,而是队列中存活时间最长的,这样就可以腾出空间给新提交的任务,但同理它也存在一定的数据丢失风险。