线程池的学习(二)
四种常见的线程池,本章节来讲讲这四种线程池:
- CachedThreadPool:可缓存的线程池
- SecudleThreadPool:周期性执行任务的线程池
- SingleThreadPool:单线程线程池
- FixedThreadPool:定长的线程池
(1). newCachedThreadPool
- 创建一个可缓存线程池;
- 如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
- 线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
- CachedThreadPool适用于处理大量、耗时少的任务。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CachedThreadDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int temp = i;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+",i:" + temp);
}
});
}
}
}
运行结果如下:
执行方法图片来源:https://blog.csdn.net/qq_36299025/article/details/89490858
(2). SecudleThreadPool
- 创建一个周期线程池,支持定时及周期性任务执行。
延迟执行3秒执行:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThreadDemo {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
for (int i = 0; i < 10; i++) {
final int temp = i;
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+",i:" + temp);
}
},3, TimeUnit.SECONDS);//表示延迟3秒执行
}
}
}
定时任务,延迟1秒后每10秒执行一次。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThreadDemo {
public static volatile int no=0;
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
for (int i = 0; i < 10; i++) {
final int temp = i;
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {//表示延迟1秒后每10秒执行一次。
@Override
public void run() {
++no;
System.out.println(Thread.currentThread().getName()+",i:" + temp+"第"+no+"次数执行");
}
},1,10, TimeUnit.SECONDS);
}
}
}
(3).SingleThreadPool
- 利用SingleThreadExecutor最多只能保证在本应用范围内,一个资源同时只会有一个线程在访问。
- 并不能保证其他应用不会对该资源进行访问
- 它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
- 结果依次输出,相当于顺序执行各个任务。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SingleThreadDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int temp = i;
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+",i:" + temp);
}
});
}
}
}
(4).FixedThreadPool
- 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
- 定长线程池的大小最好根据系统资源进行设置
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FixedThreadDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int temp = i;
executorService.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
System.out.println(Thread.currentThread().getName()+",i:" + temp);
}
});
}
}
}
以上是四个已经定义的过的线程池
----------------------------------------------------分隔符----------------------------------------------------
那么接下来,见证奇迹的时候到了,自定义线程
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ExecutorsTest {
public static void main(String[] args) {
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(1,3,3, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(5));
poolExecutor.execute(new TaskThread("1"));
poolExecutor.execute(new TaskThread("2"));
poolExecutor.execute(new TaskThread("3"));
poolExecutor.execute(new TaskThread("4"));
poolExecutor.execute(new TaskThread("5"));
poolExecutor.execute(new TaskThread("6"));
poolExecutor.execute(new TaskThread("7"));
poolExecutor.execute(new TaskThread("8"));
poolExecutor.execute(new TaskThread("9"));
poolExecutor.shutdown();
}
}
class TaskThread implements Runnable{
private String threadNmae;
public TaskThread(String name){
this.threadNmae = name;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+ " name= "+this.threadNmae);
}
}
上面的代码中,
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(1,3,3, TimeUnit.SECONDS,new LinkedBlockingDeque<>(5));
对应的源码:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {...}
即:核心线程数(corePoolSize)为1,最大线程数(maximumPoolSize)为3,线程池维护线程所允许的空闲时间 (keepAliveTime)为3,单位(unit)秒,阻塞队列(workQueue)为LinkedBlockingDeque<>(5);
扩展说明:
无论创建那种线程池 必须要调用ThreadPoolExecutor
线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue workQueue, RejectedExecutionHandler handler)
corePoolSize: 线程池维护线程的最少数量
maximumPoolSize:线程池维护线程的最大数量
keepAliveTime: 线程池维护线程所允许的空闲时间
unit: 线程池维护线程所允许的空闲时间的单位
workQueue: 线程池所使用的缓冲队列
handler: 线程池对拒绝任务的处理策略
一个任务通过 execute(Runnable)方法被添加到线程池,任务就是一个 Runnable类型的对象,任务的执行方法就是 Runnable类型对象的run()方法。
当一个任务通过execute(Runnable)方法欲添加到线程池时:
如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。
也就是:处理任务的优先级为:
核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
拒绝处理时候会抛出异常:意思说当前执行的线程数总数 大于 线程池维护线程的最大数量 + 线程池所使用的缓冲队列所能容纳的最大线程数
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.example.study04.demo4.TaskThread@1be6f5c3 rejected from java.util.concurrent.ThreadPoolExecutor@6b884d57[Running, pool size = 3, active threads = 3, queued tasks = 3, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at com.example.study04.demo4.ExecutorsTest.main(ExecutorsTest.java:17)
handler有四个选择:
ThreadPoolExecutor.AbortPolicy() 抛出java.util.concurrent.RejectedExecutionException异常
ThreadPoolExecutor.CallerRunsPolicy() 重试添加当前的任务,他会自动重复调用execute()方法
ThreadPoolExecutor.DiscardOldestPolicy() 抛弃旧的任务
ThreadPoolExecutor.DiscardPolicy() 抛弃当前的任务