线程的缺点:
定义:使用池化技术来管理和使用线程的技术,就叫做线程池
创建方式一:创建固定个数的线程池
package ThreadPool;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo45 {
public static void main(String[] args) {
// 创建固定个数的线程池
ExecutorService service = Executors.newFixedThreadPool(5); // 创建10个线程的线程池
// 执行任务
for (int i = 0; i < 10; i++) {
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程名:" + Thread.currentThread().getName());
}
});
}
}
}
package ThreadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
public class ThreadPoolDemo46 {
public static void main(String[] args) {
// 实例化线程工程
MyThreadFactory myThreadFactory = new MyThreadFactory();
// 创建固定个数的线程池
ExecutorService service
= Executors.newFixedThreadPool(10, myThreadFactory); // 创建10个线程的线程池
for (int i = 0; i < 10; i++) {
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程名:" + Thread.currentThread().getName()
+ "线程优先级:" + Thread.currentThread().getPriority());
}
});
}
}
// 线程计数器
private static int count = 1;
// 线程工厂
static class MyThreadFactory implements ThreadFactory{
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("myThreadPool-" + count++); // 修改线程名字
thread.setPriority(10); // 设置线程池的优先级
return thread;
}
}
}
创建方式二:创建带缓存的线程池
package ThreadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 创建带缓存的线程池
* **/
public class ThreadPoolDemo47 {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程名:" + Thread.currentThread().getName());
}
});
}
}
}
创建方式三:创建可以执行定时任务的线程池
package ThreadPool;
import java.util.Date;
import java.util.concurrent.*;
public class ThreadPoolDemo48 {
public static void main(String[] args) {
// 有计划的(执行定时任务的线程)
ScheduledExecutorService service =
Executors.newScheduledThreadPool(10);
System.out.println("执行任务之前:" + new Date());
// 执行任务
// 执行固定周期的任务
service.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
System.out.println("执行任务的时间:" + new Date());
}
},1,3, TimeUnit.SECONDS);
}
}
service.schedule() 方法 的区别:
1、没有延迟执行的时间设置
2、定时任务只能执行一次
scheduleWithFixedDelay() 任务开始时间事宜 上次执行任务的结束时间 作为 开始时间的
service.scheduleAtFixedRate() 任务开始时间是以 上次任务的起始时间 作为 开始时间的
线程池创建方式四:创建单个执行定时任务的线程池
package ThreadPool;
import java.util.Date;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolDemo51 {
public static void main(String[] args) {
// 创建单个执行定时任务的线程池
ScheduledExecutorService service =
Executors.newSingleThreadScheduledExecutor();
// 开启定时任务
service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行任务:" + new Date());
}
}, 1, 3, TimeUnit.SECONDS);
}
}
线程池创建方式五:创建单个线程的线程池
package ThreadPool;
import java.util.Date;
import java.util.concurrent.*;
public class ThreadPoolDemo52 {
public static void main(String[] args) {
// 创建单个执行定时任务的线程池
ExecutorService service =
Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("执行任务:" +
Thread.currentThread().getName());
}
});
}
}
}
线程池创建方式六(JDK8+):根据当前的工作环境(CPU核心数、任务量)—— 异步线程池
同步(synchronized):按照某种规则按需执行就叫做同步
同步执行的流程:
1、main调用线程池
2、线程执行完之后
3、关闭线程池,main也会随之关闭
异步执行的流程:
1、main调用异步线程池
2、异步线程池后台执行,对于main线程来说认为异步线程池已经完成,所以会关闭main线程
如果想要等待异步线程池,通过service.isTreminated()
判断当前线程池是否为终止状态
package ThreadPool;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo53 {
public static void main(String[] args) {
// 根据当前工作环境来创建线程
ExecutorService service =
Executors.newWorkStealingPool();
for (int i = 0; i < 10; i++) {
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程名:" +
Thread.currentThread().getName());
}
});
}
// 等待异步线程执行完成(根据线程池的终止状态)
while ( !service.isTerminated()){
// 自旋
}
}
}
线程池创建方式七(最常用的):
使用 Executors 创建线程池的问题:
1、线程数量不可控(线程的过度切换和争取 -> 程序执行比较慢)
2、任务数量不可控(任务数量无限次大时 Integer.MAX_VALUE(或是任务量比较大的时候)会造成内存溢出异常(OOM))
Executors 本身也是调用了 ThreadPoolExecutor来实现的
使用最原始的创建线程池的方法:
package ThreadPool;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolDemo55 {
public static void main(String[] args) {
// 原始的创建线程池的方法
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, 10, 60, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(1000)
);
// 核心线程数
// 最大线程数 (一定要大于等于核心线程数): 在非正常情况下,能创建的最大线程数
// 最大存货时间
// 时间单位
// 阻塞队列(一定要给任务队列设置容量,如果不设置容量,就会出现OOM)
for (int i = 0; i < 5; i++) {
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程名称:" +
Thread.currentThread().getName());
}
});
}
}
}
使用原始的创建线程池的方法修改线程名(线程工厂):
package ThreadPool;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolDemo56 {
private static int count = 1;
public static void main(String[] args) {
ThreadFactory threadFactory = new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("myThreadPool" + count++);
return t;
}
};
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, 5, 0, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(1000),
threadFactory
);
// 执行任务
for (int i = 0; i <5 ; i++) {
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程名:" + Thread.currentThread().getName() );
}
});
}
}
}
使用拒绝策略创建线程池:
JDK提供了4种拒绝策略
ThreadPoolExecutor.AbortPolicy()
)package ThreadPool;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolDemo57 {
// 默认拒绝策略
public static void main(String[] args) {
// 创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, 5, 0, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(5)
);
for (int i = 0; i < 11; i++) {
int finalI = i;
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println("任务数:" + finalI
+ "线程名:" +Thread.currentThread().getName());
}
});
}
}
}
ThreadPoolExecutor.CallerRunsPolicy
)—— 一般可理解为:使用主线程来执行任务package ThreadPool;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreradPoolDemo58 {
// 默认拒绝策略
public static void main(String[] args) {
// 创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, 5, 0, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(5),
new ThreadPoolExecutor.CallerRunsPolicy()
);
for (int i = 0; i < 15; i++) {
int finalI = i;
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println("任务数:" + finalI
+ "线程名:" +Thread.currentThread().getName());
}
});
}
}
}
ThreadPoolExecutor.DiscardPolicy
) —— 会忽略新来的任务,而不是任务队列里的任务ThreadPoolExecutor.DiscardOldestPolicy
) —— 忽略最先加入到任务队列里的任务自定义拒绝策略:
package ThreadPool;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreradPoolDemo60 {
// 默认拒绝策略
public static void main(String[] args) {
// 创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, 5, 0, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(5),
// 自定义拒绝策略
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("执行了自定义拒绝策略");
}
}
);
for (int i = 0; i < 15; i++) {
int finalI = i;
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println("任务数:" + finalI
+ "线程名:" +Thread.currentThread().getName());
}
});
}
}
}
线程池的特征:线程池相比于线程来说是长生命周期的,即使没有任务了,也会运行并等待任务。
executor.shutdown
:会拒绝新任务加入,等待线程池中的任务队列执行完成之后,再停止线程池executor.shutdownNow()
:会拒绝执行新任务,不等待任务队列中的任务执行完成,就停止线程池executor.shutdown
后会进入 SHUTDOWN 状态executor.shutdownNow()
后会进入 STOP 状态1、线程池的优点
2、线程池的7种创建方式(ThreadPoolExecutor 重点)
3、ThreadPoolExecutor 的优点【解决了:a. 线程数量不可控问题;b.任务数量不可控问题】
4、ThreadPoolExecutor 7个参数的顺序和参数说明
5、ThreadPoolExecutor 执行流程
6、ThreadPoolExecutor 拒绝策略(5种)
7、线程池的状态和停止方法