为什么要使用线程池?
线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后再线程创建后启动这些任务如果线程的数量超过最大数量,超过数量的线程将排队等候,等其他线程执行完毕,再从队列中取出任务来执行
特点:线程复用,控制最大并发数,管理线程
一、降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗
二、提高响应速度,当任务到达时,任务可以不需要的等到线程创建就能够立刻执行
三、提高线程的可管理性,线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,
还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
创建线程的前两种方法:继承Thread类,实现Runnable接口
创建线程的第三种方法:使用Callable创建线程:
public class Test {
public static void main(String[] args) throws Exception{
FutureTask<Integer> futureTask = new FutureTask<>(new Thre());
Thread thread = new Thread(futureTask,"AAA");
thread.start();
while (!futureTask.isDone()){
}
System.out.println(futureTask.get());
}
}
class Thre implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("哈哈哈");
return 1024;
}
}
创建线程的第四种方法(企业常用):使用线程池创建线程
public static void main(String[] args){
ExecutorService threadPool = Executors.newFixedThreadPool(5);
//ExecutorService executorService = Executors.newSingleThreadExecutor();
//ExecutorService executorService1 = Executors.newCachedThreadPool();
//模拟10个用户办理业务,
try {
for (int i = 0; i < 20; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"办理业务");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
下面分析一下
(1)Executors.newFixedThreaPool(5);
源码:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
(2)Executors.newSingleThreadExecutor()
源码:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
(3)Executors.newCachedThreadPool();
源码:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
上述线程池创建时底层都是五个参数,接着往下看ThreafPoolExecutor源码:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
我们发现,它调用了一个this方法,即它的构造函数,是传的7个参数,点进this方法,源码:
public ThreadPoolExecutor(int corePoolSize, //1
int maximumPoolSize, //2
long keepAliveTime, //3
TimeUnit unit, //4
BlockingQueue<Runnable> workQueue, //5
ThreadFactory threadFactory, //6
RejectedExecutionHandler handler) { //7
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
我们可以清楚的看到,传的是7个参数。下面详细讲解这七大参数:
1.corePoolSize:线程池中的常驻核心线程数
在创建了线程池后,当有请求任务进来之后,就会安排池中的线程去执行请求任务,近似理解为今日当值线程
当线程池中的线程数目达到corePoolSize后,就会把到达的任务放入缓存队列中。
2.maximumPoolSize:线程池能够容纳同时执行的最大线程数,此值必须大于等于1
3.keepAliveTime:多余的空闲线程的存活时间。
当前线程池数量超过corePoolSize时,当空闲时间达到keepAliveTime值时,
多余空闲线程会被销毁直到只剩下corePoolSize个线程为止
默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池找那个的线程数不大于corePoolSize。
4.unit:keepAliveTime的单位
5.workQueue:任务队列,被提交但尚未被执行的任务
6.threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般默认即可
7.handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池最大线程数(maximumPoolSize)时如何处理
以上可对比银行网点的办理模式,在这就不详细说了哦,想通了也就完全理解了!!!