目录
一、线程池的作用
二、线程池的关系图
三、线程池的创建及参数
四、线程池的使用原理
五、线程池的使用
一、线程池的作用
随着cpu核数越来越多,不可避免的利用多线程技术以充分利用其计算能力。所以,多线程技术是服务端开发人员必须掌握的技术。线程的创建和销毁,都涉及到系统调用,比较消耗系统资源,所以就引入了线程池技术,线程池中有已经创建好的线程,可直接使用,并且使用完了,直接再次放回线程池,避免频繁的线程创建和销毁。
二、线程池的关键类的关系图
从上面可以看出Java的线程池主的实现类主要有两个类ThreadPoolExecutor和ForkJoinPool。
ForkJoinPool是Fork/Join框架下使用的一个线程池,一般情况下,我们使用的比较多的就是ThreadPoolExecutor。我们大多数时候创建线程池是通过Executors
三、线程池的创建和参数解析
先看一个参数最完整的创建线程池的构造方法
参数解析:
①corePoolSize:线程池的核心线程数,说白了就是,即便是线程池里没有任何任务,也会有corePoolSize个线程在候着等任务。
②maximumPoolSize:最大线程数,不管你提交多少任务,线程池里最多工作线程数就是maximumPoolSize。
③keepAliveTime:线程的存活时间。当线程池里的线程数大于corePoolSize时,如果等了keepAliveTime时长还没有任务可执行,则线程退出。
⑤unit:这个用来指定keepAliveTime的单位,比如秒:TimeUnit.SECONDS。
⑥workQueue:一个阻塞队列,提交的任务将会被放到这个队列里。
⑦threadFactory:线程工厂,用来创建线程,主要是为了给线程起名字,默认工厂的线程名字:pool-1-thread-3。
⑧handler:拒绝策略,当线程池里线程被耗尽,且队列也满了的时候会调用。
线程池创建:
java.util.concurrent.Executosr是线程池的静态工厂,我们通常使用它方便地生产各种类型的线程池,主要的方法有四种:
1、newSingleThreadExecutor()——创建一个单线程的线程池
2、newFixedThreadPool(int n)——创建一个固定大小的线程池
3、newCachedThreadPool()——创建一个可缓存的线程池
4、newScheduledThreadPool()——创建一个固定线程数的线程池,支持定时及周期性执行后台任务。
(1)newSingleThreadExecutor()单线程数的线程池
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(),
threadFactory));
最关键的是corePoolSize(核心线程数)参数和maximumPoolSize(最大线程数)两个参数都是1
(2)newFixedThreadPool()固定线程数的线程池
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(),
threadFactory);
可以看出corePoolSize(核心线程数)参数和maximumPoolSize(最大线程数)两个参数都是相等
(3)newCachedThreadPool()创建一个可以根据需要创建新线程的线程池,它是没有线程数量限制的
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue(),
threadFactory);
}
corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE(认为是无限大)keepAliveTime=60s,当60s秒后没有任务执行的线程将会退出,由于CachedThreadPool线程没有上线,无线创建线程需要大量的内存,需要谨慎使用
(4)newScheduledThreadPool():创建一个固定线程数的线程池,支持定时及周期性执行后台任务。这个用的比较少,就略过
四、线程池的运行原理
用一张图来描述线程池执行的流程
该图对应如下源码:
五、线程池使用
实例
(1)newSingleThreadExecutor
MyThread.java
public class MyThread extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName() + "正在执行。。。");
}
}
ThreadPoolTest.java
ThreadPoolTest.java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolTest {
public static void main(String[] args) {
//创建一个可重用固定线程数的线程池
ExecutorService pool = Executors. newSingleThreadExecutor();
//创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
Thread t4 = new MyThread();
Thread t5 = new MyThread();
//将线程放入池中进行执行
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
//关闭线程池
pool.shutdown();
}
}
运行结果:
(2)newFixedThreadPool
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolTest {
public static void main(String[] args) {
//创建一个可重用固定线程数的线程池
//ExecutorService pool = Executors. newSingleThreadExecutor();
//固定线程池大小
ExecutorService pool = Executors.newFixedThreadPool(2);
//创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
Thread t4 = new MyThread();
Thread t5 = new MyThread();
//将线程放入池中进行执行
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
//关闭线程池
pool.shutdown();
}
}
运行结果:
(3)newCachedThreadPool
根据上面一样,只修改一句话
//创建一个可重用固定线程数的线程池
ExecutorService pool = Executors.newCachedThreadPool();
运行结果:
好了,线程池的简单介绍先到这里,如有不对,请多多指教。