一、认识线程池
1.1、什么是线程池?
线程池就是一个可以复用线程的技术。
1.2、不使用线程池的问题
用户每发起一个请求,后台就需要创建一个新线程来处理,下次新任务来了肯定又要创建新线程处理的,创建新线程的开销是很大的,并且请求过多时,肯定会产生大量的线程出来,这样会严重影响系统的性能。
1.3、线程池的工作原理

二、创建线程池
JDK5.0起提供了代表线程池的接口:ExecutorService。
2.1、如何创建线程池对象?
方式一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象。
方式二:使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象。
2.2、方式一:通过 ThreadPoolExecutor 创建线程池
2.2.1、介绍

1、什么时候开始创建临时线程?
新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程。
2、什么时候会拒绝新任务?
核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始拒绝任务。
3、任务拒接策略

2.2.2、示例
1、处理 Runnable 任务
ExecutorService的常用方法

import java.util.concurrent.*;
public class ExecutorServiceDemo1 {
public static void main(String[] args) {
// 目标:创建线程池对象来使用。
// 1、使用线程池的实现类ThreadPoolExecutor声明七个参数来创建线程池对象。
ExecutorService pool = new ThreadPoolExecutor(3, 5,
10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
// 2、使用线程池处理任务!看会不会复用线程?
Runnable target = new MyRunnable();
pool.execute(target); // 提交第1个任务 创建第1个线程 自动启动线程处理这个任务
pool.execute(target); // 提交第2个任务 创建第2个线程 自动启动线程处理这个任务
pool.execute(target); // 提交第2个任务 创建第3个线程 自动启动线程处理这个任务
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target); // 到了临时线程的创建时机了
pool.execute(target); // 到了临时线程的创建时机了
pool.execute(target); // 到了任务拒绝策略了,忙不过来
// 3、关闭线程池 :一般不关闭线程池。
// pool.shutdown(); // 等所有任务执行完毕后再关闭线程池!
// pool.shutdownNow(); // 立即关闭,不管任务是否执行完毕!
}
}
// 1、定义一个线程任务类实现Runnable接口
public class MyRunnable implements Runnable {
// 2、重写run方法,设置线程任务
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "输出:" + i);
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
2、处理Callable任务
ExecutorService的常用方法

import java.util.concurrent.*;
public class ExecutorServiceDemo2 {
public static void main(String[] args) {
// 目标:创建线程池对象来使用。
// 1、使用线程池的实现类ThreadPoolExecutor声明七个参数来创建线程池对象。
ExecutorService pool = new ThreadPoolExecutor(3, 5,
10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
// 2、使用线程池处理Callable任务!
Future<String> f1 = pool.submit(new MyCallable(100));
Future<String> f2 = pool.submit(new MyCallable(200));
Future<String> f3 = pool.submit(new MyCallable(300));
Future<String> f4 = pool.submit(new MyCallable(400));
try {
System.out.println(f1.get());
System.out.println(f2.get());
System.out.println(f3.get());
System.out.println(f4.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
import java.util.concurrent.Callable;
// 1、定义一个实现类实现Callable接口
public class MyCallable implements Callable<String> {
private int n;
public MyCallable(int n) {
this.n = n;
}
// 2、实现call方法,定义线程执行体
public String call() throws Exception {
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += i;
}
return Thread.currentThread().getName() +"计算1-" + n + "的和是:" + sum;
}
}
2.3、方式二:通过Executors 创建线程池(不推荐)
2.3.1、介绍

注意:
这些方法的底层,都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象。
Executors使用可能存在的陷阱。大型并发系统环境中使用Executors如果不注意可能会出现系统风险。

2.3.1、示例
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ExecutorsDemo3 {
public static void main(String[] args) {
// 目标:通过线程池工具类:Executors,调用其静态方法直接得到线程池
ExecutorService pool = Executors.newFixedThreadPool(3);
Future<String> f1 = pool.submit(new MyCallable(100));
Future<String> f2 = pool.submit(new MyCallable(200));
Future<String> f3 = pool.submit(new MyCallable(300));
Future<String> f4 = pool.submit(new MyCallable(400));
try {
System.out.println(f1.get());
System.out.println(f2.get());
System.out.println(f3.get());
System.out.println(f4.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
2万+

被折叠的 条评论
为什么被折叠?



