线程池的重点内容:
-
线程池的优点
-
线程池的七种创建方式
-
ThreadPoolExecutor(线程数不可控,任务数不可控)
-
ThreadPoolExecutor七个参数顺序和参数说明
-
核心线程数
-
最大线程数
-
生存时间
-
时间单位
-
任务队列
-
线程工厂(优先级 命名 类型)
-
拒绝策略
-
-
ThreadPoolExecutor拒绝策略(五种)
-
默认拒绝策略(不执行任务,直接抛出异常)
-
使用调用者线程执行任务(使用主线程来执行任务)
-
忽略最新任务(不会报错)
-
舍弃老任务
-
自定义拒绝策略
-
-
线程池的状态和停止方法
线程缺点
-
线程的创建会开辟本地方法栈、虚拟机栈、程序计数器线程私有的内存,同时销毁的时候会消耗以上三个区域,因此频繁的创建和销毁比较消耗系统资源
-
在任务量远远大于线程可以处理的任务量的时候,并不能友好拒绝任务
引出线程池:
java.util.concurrent
并发类都会放在juc下
线程池的创建方式分为七种:
public class ThreadPoolDemo45 {
public static void main(String[] args) {
// 创建固定个数的线程池
ExecutorService service = Executors.newFixedThreadPool(1);
// 定义任务
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("线程名:" +
Thread.currentThread().getName());
}
};
// 执行任务
service.execute(runnable);
service.execute(runnable);
service.execute(runnable);
service.execute(runnable);
service.execute(runnable);
service.execute(runnable);
service.execute(runnable);
service.execute(runnable);
service.execute(runnable);
service.execute(runnable);
}
}
public class ThreadPoolDemo47 {
public static void main(String[] args) {
// 创建带缓存的线程池
ExecutorService service = Executors.newCachedThreadPool();
// 执行 10 个任务
for (int i = 0; i < 100; i++) {
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程名:" +
Thread.currentThread().getName());
}
});
}
}
}
public class ThreadPoolDemo49 {
public static void main(String[] args) {
// 创建一个执行定时任务的线程池
ScheduledExecutorService service =
Executors.newScheduledThreadPool(10);
System.out.println("执行任务之前:" + new Date());
// 执行任务
service.schedule(new Runnable() {
@Override
public void run() {
System.out.println("执行任务:" + new Date());
}
}, 3, TimeUnit.SECONDS);
}
}
public class ThreadPoolDemo50 {
public static void main(String[] args) {
// 创建一个执行定时任务的线程池
ScheduledExecutorService service =
Executors.newScheduledThreadPool(10);
// 执行任务
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);
}
}
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);
}
}
PS:面试题:创建单个线程的线程池有什么用?1.使用池化技术,可以避免频繁创建和销毁线程带来的性能开销2.线程池中都有一个任务队列,有任务队列可以存储多余的任务(更好地分配和执行任务)3.当有大量的任务不能处理的时候,线程池可以自定义拒绝策略,友好的执行拒绝策略4.线程池可以更好的管理任务
1.发请求
2.等待执行完成
3.结果返回
1.发请求
2.执行完成
3.另一个程序异步处理
4.处理完成后调用回调函数返回结果
ThreadPoolExecutor七个参数顺序和参数说明
-
核心线程数
-
最大线程数
-
生存时间
-
时间单位
-
任务队列
-
线程工厂(优先级 命名 类型)
-
拒绝策略
ThreadPoolExecutor执行流程
线程池里有两个重要的对象:
1.线程
2.工作(任务)队列(工作队列的长度为Integer.MAX_VALUE)
如果使用前六种使用Executors创建线程池的方式会导致的问题:
1.线程数量不可控(比如创建带缓存的线程池)
2.工作任务量不可控(Integer.MAX_VALUE),可能会导致内存溢出
拒绝策略:
线程池关闭
1.shutdown()
调用shutdown()后会拒绝执行新任务,等待线程池中的任务队列执行完之后再停止线程池
2.shutdownNow()
调用shutdownNow()后会拒绝执行新任务,不会等待任务队列的任务执行完成,就停止线程池
线程池状态(5个):
不等于线程状态(6种)
private static final int RUNNING = -1 << COUNT_BITS;(不管有没有任务都是running)
private static final int SHUTDOWN = 0 << COUNT_BITS;(调用shutdown())
private static final int STOP = 1 << COUNT_BITS;(调用shutdownNow())
private static final int TIDYING = 2 << COUNT_BITS;(pool是空的时候)
private static final int TERMINATED = 3 << COUNT_BITS;(销毁状态)