线程使用存在的问题
- 如果并发的线程数量很多, 并且每个线程都是执行一个时间很短的任务就结束了, 这样频繁创建线程就会大大降低系统的效率, 因为频繁创建线程和销毁线程需要时间
- 如果大量线程在执行, 会涉及到线程间上下文的切换, 会极大的消耗CPU运算资源
线程池
- 其实就是一个容纳多个线程的容器, 其中的线程可以反复使用, 省去了频繁创建线程对象的操作, 无需反复创建线程而消耗过多资源
线程池使用大致流程
- 创建线程池指定线程开启的数量
- 提交任务给线程池, 线程池中的线程就会获取任务, 进行处理任务
- 线程处理完任务, 不会销毁, 而是返回到线程池中, 等待下一个任务执行
- 如果线程池中的所有线程都被占用, 提交的任务, 只能等待线程池中的线程处理完当前任务
使用线程池的好处
- 降低资源消耗 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务
- 提高响应速度 当任务到达时, 任务可以不需要等待线程创建 , 就能立即执行
- 提高线程的可管理性 可以根据系统的承受能力, 调整线程池中工作线线程的数目, 防止因为消耗过多的内存, 服务器死机 (每个线程需要大约1MB内存, 线程开的越多, 消耗的内存也就越大, 最后死机)
线程池处理Runnable任务
- 创建线程池
- java.util.concurrent.ExecutorService 是线程池接口类型, 使用时我们不需自己实现, JDK已经帮我们实现好了, 获取线程池我们使用工具类java.util.concurrent.Executors的静态方法:
- public static ExecutorService newFixedThreadPool (int num) 指定线程池最大线程池数量获取线程池
- 提交任务
- Future submit(Callable task)
- Future<?> submit(Runnable task)
- 关闭线程池方法(一般不使用关闭方法,除非后期不用或者很长时间都不用,就可以关闭)
- void shutdown() 启动一次顺序关闭, 执行以前提交的任务, 但不接受新任务
public class Test1 {
public static void main(String[] args) {
// 获取线程池
ExecutorService threadPool = Executors.newFixedThreadPool(3);
// 给线程池提交任务
threadPool.submit(new Student("p1"));
threadPool.submit(new Student("p2"));
threadPool.submit(new Student("p3"));
threadPool.submit(new Student("p4"));
threadPool.submit(new Student("p5"));
// 关闭线程池
threadPool.shutdown();
}
}
class Student implements Runnable {
private String name;
public Student(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "正在教" + name + "游泳");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程池处理Callable任务
public class Test2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 创建线程池
ExecutorService threadPool = Executors.newFixedThreadPool(5);
// 为线程池提交任务
Future<Integer> future = threadPool.submit(new Calc(100));
Integer result = future.get();
System.out.println(result);
}
}
class Calc implements Callable<Integer> {
private int n;
public Calc(int n) {
this.n = n;
}
@Override
public Integer call(){
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += i;
}
return sum;
}
}
自定义创建线程池对象
-
ThreadPoolExecutor线程池类
public ThreadPoolExecutor( int corePoolSize, -- 核心线程数量 int maximumPoolSize, -- 最大线程数量 long keepAliveTime, -- 临时线程存活时间 TimeUnit unit, -- 临时线程存活时间单位 BlockingQueue<Runnable> workQueue, -- 阻塞队列 ThreadFactory threadFactory, -- 创建线程的方式 RejectedExecutionHandler handler -- 取舍模式 )
public class Test3 {
public static void main(String[] args) {
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
3, // 核心线程数量
10, // 最大线程数量
60, // 临时线程存活时间
TimeUnit.SECONDS, // 临时线程存活时间单位
new ArrayBlockingQueue<>(20), // 阻塞队列
Executors.defaultThreadFactory(), // 创建线程的方式
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);
for (int i = 0; i < 40; i++) {
threadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("任务执行");
}
});
}
}
}