线程池原理&常用四大线程池及七大参数

线程池原理&常用四大线程池及七大参数

目录

前言常用的四种线程池newCachedThreadPool——可缓存线程池newFixedThreadPool————指定线程数量newSingleThreadExecutor————单线程的ExecutornewScheduleThreadPool——定时线程池

线程池七大参数corePoolSize——核心线程最大数maximumPoolSize——线程池最大线程数keepAliveTime——空闲线程存活时间。unit——空闲线程存活时间单位workQueue——等待队列threadFactoryhandler——拒绝策略

线程池工作流程

前言

最近在面试,关于一些多线程的内容,细致的部分很容易就想不起来具体应该怎么回答。翻开之前的笔记本,感觉就在眼前,知识不去实践,就像是别人的。尤其是程序猿这行,源源不断的新技术,就不要做捡了芝麻丢了西瓜的人。 总结在博客上,也能再温习一下。用不用的先门清~

常用的四种线程池

newCachedThreadPool——可缓存线程池

描述:

如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

特点

线程的创建数量几乎没有限制。这样可灵活的往线程池中添加线程。如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程要注意控制任务的数量,否则,由于大量线程同时运行,很有会造成系统瘫痪。

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class executor {

public static void main(String[] args) {

ExecutorService pool = Executors.newCachedThreadPool();

for (int i = 0; i < 10; i++) {

final int index = i;

try {

Thread.sleep(index*1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

pool.execute(new Runnable() {

public void run() {

System.out.println(index);

}

});

}

}

}

newFixedThreadPool————指定线程数量

描述:

创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。

优点:

提高程序效率和节省创建线程时所耗的开销

缺点:

线程池空闲时,即线程池中没有可运行任务时,它不会释放工作线程,还会占用一定的系统资源

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class fixedThreadPool {

public volatile int i;

public static void main(String[] args) {

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);

for (int i = 0; i < 10; i++) {

final int index = i;

fixedThreadPool.execute(new Runnable() {

public void run() {

try {

System.out.println(index);

Thread.sleep(8000);

} catch (Exception e) {

e.printStackTrace();

}

}

});

}

}

}

运行结果:两个线程一起执行,隔8s切换

newSingleThreadExecutor————单线程的Executor

描述:

只创建唯一的线程来执行任务。保证任务按照指定顺序(FIFO,LIFO,优先级)执行。如果这个线程异常结束,会有另一个取代它

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class singleThreadExecutor {

public static void main(String[] args) {

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

for (int i = 0; i < 10; i++) {

final int index = i;

singleThreadExecutor.execute(new Runnable() {

public void run() {

try {

System.out.println(index);

Thread.sleep(8000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

});

}

}

}

运行:单线程运行

newScheduleThreadPool——定时线程池

描述:

支持定时及周期性任务执行。

栗子:

延迟3s执行示例代码

import java.sql.Time;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;

public class scheduledThreadPool {

public static void main(String[] args) {

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);

scheduledThreadPool.schedule(new Runnable() {

public void run() {

System.out.println("延迟5秒执行");

}

},5, TimeUnit.SECONDS);

}

}

栗子:

延迟2秒后每5秒执行一次,定期执行示例代码

import java.sql.Time;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;

public class scheduledThreadPool {

public static void main(String[] args) {

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);

scheduledThreadPool.scheduleAtFixedRate(new Runnable() {

public void run() {

System.out.println("延迟5秒执行");

}

},2,5,TimeUnit.SECONDS);

}

}

运行:

线程池七大参数

corePoolSize——核心线程最大数

maximumPoolSize——线程池最大线程数

keepAliveTime——空闲线程存活时间。

当一个非核心线程被创建,使用完归还给线程池一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁,这里的指定时间由 keepAliveTime来设定

unit——空闲线程存活时间单位

这是keepAliveTime的计量单位

workQueue——等待队列

当线程池满了,线程就会放入这个队列中。任务调度再取出

jdk提供四种工作队列

ArrayBlockingQueue——基于数组的阻塞队列,按FIFO,新任务放队尾

有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。 LinkedBlockingQuene——基于链表的无界阻塞队列,按照FIFO排序

其实最大容量为Interger.MAX由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而不会去创建新线程直到maxPoolSize,因此使用该工作队列时,参数maxPoolSize其实是不起作用的 SynchronousQuene——不缓存任务的阻塞队列

生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略 PriorityBlockingQueue——具有优先级的无界阻塞队列

优先级通过参数Comparator实现。

threadFactory

创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等

handler——拒绝策略

当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,就用到拒绝策略 jdk中提供了4中拒绝策略

CallerRunsPolicy——主线程自己执行该任务

该策略下,在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,否则直接抛弃任务。 AbortPolicy——抛出异常

该策略下,直接丢弃任务,并抛出RejectedExecutionException异常 DiscardPolicy——直接丢弃

该策略下,直接丢弃任务,什么都不做 DiscardOldestPolicy——早删晚进

该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列

线程池工作流程

线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。当调用 execute() 方法添加一个任务时,线程池会做如下判断:

如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;如果队列满了,而且正在运行的线程数量等于 maximumPoolSize,那么线程池会抛出异常 RejectExecutionException。 当一个线程完成任务时,它会从队列中取下一个任务来执行。当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

相关推荐

为什么这么多中国人都是无神论者?他们相信什么代替信上帝?
英格兰VS瑞士:欧洲杯史诗对决,关键战役即将上演
bt365验证不通过

英格兰VS瑞士:欧洲杯史诗对决,关键战役即将上演

📅 06-27 👁️ 9158
刷机工具大合集2025/6/13 10:21:00导言
be365是否安全

刷机工具大合集2025/6/13 10:21:00导言

📅 07-03 👁️ 3094