线程池
使用线程池的目的
(1)线程时稀缺资源,不能频繁创建
(2)解耦,把运行和创建销毁线程分离开了
(3)线程可以复用
线程池原理
核心思想就是把宝贵的资源放到一个池子里,每次使用都从里面获取,用完之后放回池子*其他人使用
Executors 的调用线程池的方法
(1)线程池的分类
static ExecutorService |
newFixedThreadPool(int nThreads)
创建一个线程池,该线程池重用固定数量的从共享*队列中运行的线程。 |
static ExecutorService |
newCachedThreadPool() (可变大小线程池)
创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。 |
static ExecutorService |
newSingleThreadExecutor() (减少线程的创建和销毁的开销,实现了重用性)
创建一个使用从*队列运行的单个工作线程的执行程序。 |
static ScheduledExecutorService |
newScheduledThreadPool(int corePoolSize)
创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执 |
(2)使用
定义一个线程
public class TaskDemo implements Runnable{
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" is running");
}
}
定义四种线程池
FixedPoolDemo
public class FixedPoolDemo {
public static void main(String[] args) {
//创建固定大小的线程池
ExecutorService pool = Executors.newFixedThreadPool(5);
//创建十个任务给线程池
for (int i = 0; i < 10; i++) {
TaskDemo task = new TaskDemo();
//把任务交给pool去执行
pool.execute(task);
}
//关闭线程池
pool.shutdown();
}
}
CachePool
//可变大小的
public class CachePool {
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
TaskDemo task = new TaskDemo();
//把任务交给pool去执行
pool.execute(task);
}
}
}
SingletonPool
public class SingletonPool {
public static void main(String[] args) {
ExecutorService pool = Executors.newSingleThreadExecutor();
//创建十个任务给线程池
for (int i = 0; i < 10; i++) {
TaskDemo task = new TaskDemo();
//把任务交给pool去执行
pool.execute(task);
}
//关闭线程池
pool.shutdown();
}
}
ScheduledPool
//可调度的
public class ScheduledPool {
public static void main(String[] args) {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
for (int i = 0; i < 10; i++) {
TaskDemo task = new TaskDemo();
//把任务交给pool去执行
pool.execute(task);
}
//关闭线程池
pool.shutdown();
}
}
原理
Executors方法源码
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newSingleThreadExecutor newSingleThreadExecutor newFixedThreadPool 调用的都是同一个方法new ThreadPoolExecutor()根据参数的不同来判断不同的线程池方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
核心参数
int corePoolSize : 核心线程池的基本大小
int maximumPoolSize:线程池最大线程数量
long keepAliveTime: 线程空闲后的存活时间 (控制超出corePoolSize的线程数存活的时间)
TimeUnit unit:线程保持活动的时间单位
BlockingQueue<Runnable> workQueue :用与存放任务的阻塞队列
defaultHandler :当队列和最大线程池都满了之后的饱和策略
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//32位Integer Integer.SIZE
//COUNT_BITS:表示线程数量 COUNT_BITS = 29
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
//高三位表示状态码
private static final int RUNNING = -1 << COUNT_BITS; //111
private static final int SHUTDOWN = 0 << COUNT_BITS; //000
private static final int STOP = 1 << COUNT_BITS; //001
private static final int TIDYING = 2 << COUNT_BITS; //010
private static final int TERMINATED = 3 << COUNT_BITS; //011
线程池状态
RUNNING
(1)说明:运行状态,线程池创建后就处于Running
(2) 切换:
SHUTDOWN
(1)说明 :关闭,不接受新任务,但是队列中的任务还是会完成
(2)切换:pool执行shutdown()方法时,转换成这个状态
STOP
(1)说明:停止,不接受新任务,也不执行队列中的任务。
(2)切换: pool执行shutdownNow(),转换成这个状态
TIDYING
(1)说明: 整理,
(2)
TERMINATED
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
MaxpoolSize 线程池最大线程数
CorePoolSize 核心线程池要保留在池中的线程数,即使它们处于空闲状态。生命周期与线程池生命周期相同
创建线程的方式
New Thread (代表真正意义的线程) 生命周期
Implement Runnable 对run方法进行了重写(运行的过程还是需要借助Thread, 需要把对象传递到Thread中取)
execute方法如何执行的
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
//根据位运算拿到当前线程池的状态码(高三位)
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) { //当前工作线程数量< 核心线程数量
if (addWorker(command, true)) //用一个线程处理
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) { //运行状态时,写入阻塞队列
int recheck = ctl.get(); //再次获取状态码
if (! isRunning(recheck) && remove(command))//双重检测,再次验证状态码
reject(command);//根据策略 拒绝
else if (workerCountOf(recheck) == 0)
addWorker(null, false);//执行任务
}
else if (!addWorker(command, false))//尝试新建一个线程 如果失败
reject(command);//拒绝
}
如何配置线程池
线程池肯定不是越大越好
通常时根据这批任务执行的性质来确定的
IO密集型任务:由于线程并不是一直在运行,所以可以尽可能的多配置线程,比如CPU个数*2
CPU密集型任务(大量复杂的运算)应当分配较少的线程,比如CPU个数相当的大小
线程池关闭
有运行任务自然有关闭任务 使用shutdown()/shutdownNow()
但是两者有区别
shutdown() 执行后停止接受新任务,会把队列中任务执行完
shutdownNow() 停止接受新任务,但会中断所有任务,将线程池状态变为stop
上一篇: 努力,让生命变得更厚重
下一篇: 中文分词 - php逐个汉字遍历字符串