前言
在一个应用程序中,我们需要多次使用线程,也就意味着,我们需要多次创建并销毁线程。而创建并销毁线程的过程势必会消耗内存。而在Java中,内存资源是及其宝贵的,所以,我们就提出了线程池的概念。
线程池
那么什么是线程池 ?顾名思义,线程池就是一个装线程的池子,用来管理线程的创建和回收,重复利用等等,从而达到减少内存消耗的目的。
创建线程池
线程池的最上层接口是Executor,Executor接口有一个子接口ExecutorService,ExecutorService的实现类为AbstracExecutorService,而ThreadPoolExcutor正是AbstrcExecutorService的子类。ThreadPoolExecutor是线程池的核心类,此类的构造方法如下:
//线程池最上层接口
public interface Executor {
void execute(Runnable command);
}
//创建线程使用的实现类
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
传参详解
-
corePoolSize:核心线程池大小。线程池默认存在的线程数量,即使空闲状态也不会被回收。
-
maximumPoolSize:线程最大数量。当新任务进来时,此时核心线程池和缓存队列已经,程序就会创建新的线程执行当前任务,但是数量不能大于maximumPoolSize这个值,否则会采用拒绝接收任务策略。这些线程称为非核心线程
-
keepAliveTime:非核心线程可存在的空闲时间。当非核心线程运行完毕就会进入空闲状态,空闲状态的线程超过一定时间会被回收以保证内存的节省。
-
unit:时间单位。和keepAliveTime配合使用。
-
workQueue:缓存队列,用来存放等待被执行的任务。
-
threadFactory:线程工厂,用来创建线程,一般有三种策略。
ArrayBlockingQueue; LinkedBlockingQueue; SynchronousQueue;
-
handler:拒绝策略。线程的数量大于线程最大数量就会拒绝处理任务,有以下几种策略:
ThreadPoolExecutor.AbortPolicy://不执行新任务并抛出RejectedExecutionException异常。 ThreadPoolExecutor.DiscardPolicy://不执行新任务,但是不抛出异常。 ThreadPoolExecutor.DiscardOldestPolicy://丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程) ThreadPoolExecutor.CallerRunsPolicy://直接调用executor方法来处理当前任务
线程池运行流程
当有新任务进入时,程序会先判断核心线程池是否已满,不是则创建新线程(核心线程)执行任务,如果已满就会判断缓存队列是否已满,未满则将任务存储在缓存队列中等待调用执行,如果缓存队列也满了,就会判断线程池的线程总数量是否已满,未满则创建非核心线程执行当前任务,否则就调用拒绝策略处理无法执行的任务。
常用线程池
定长线程池
定长线程池顾名思义就是固定长度的线程池。固定长度线程池有核心线程,核心线程的数据就是最大线程的数量,没有非核心线程。
示例代码
public class FixedThread {
public static void main(String[] args) {
// 创建固定长度的线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+"正在被执行!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
}
缓存线程池
可缓存的线程池,里边没有核心线程,非核心线程的数量没有上限,多少都可以。当有任务时创建线程执行任务,执行完毕线程会被回收。适用于任务量的情况。
示例代码
public class CacheThread {
public static void main(String[] args) {
// 创建可缓存的线程池
ExecutorService cacheThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cacheThreadPool.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName() + "正在被执行!");
}
});
}
}
}
单线程池
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(先进先出)执行。
示例代码
public class SingleThread {
public static void main(String[] args) {
//创建单线程池
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadPool.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+"正在被执行!打印的值是"+index);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
}
定时线程池
定时执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。
示例代码
public class ScheduledThread {
public static void main(String[] args) {
// 创建可定时的固定长度线程池
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
/**
* 延迟参数详解
* scheduledThreadPool.schedule(command, delay, unit)
* 参数1->new Runnable()
* 参数2->延迟时间
* 参数3->时间单位
*
* 定时参数详解
* scheduledThreadPool.scheduleAtFixedRate(command, initialDelay, period, unit)
* 参数1->new Runnable()
* 参数2->延迟时间
* 参数3->定时时间
* 参数4->时间单位
*/
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName() + "延迟1秒执行!");
}
}, 0,3, TimeUnit.SECONDS);
}
}
文尾
文章均为学习阶段记录笔记,若有不妥请留言指正。谢谢!