Java - 并发编程 - 线程池(图解)

前言

做的学习笔记,并加入了自己的理解,谢谢

使用线程池的原因

我们创建的线程在运行结束后都会被虚拟机销毁,如果线程数量多的话,频繁的创建和销毁线程会大大浪费时间和效率,更重要的是浪费内存,线程池可以让线程运行后不立刻销毁,而是让线程重复使用,继续执行其他任务

线程池的优化

  1. 降低资源消耗
  2. 提高响应速度
  3. 提高线程的可管理性

流程图

img

线程池的核心参数

/**
 * 线程核心参数
 * @param corePoolSize    核心线程数量
 * @param maximumPoolSize 最大线程数量
 * @param keepAliveTime   线程空间后的存活时间
 * @param unit            时间单位
 * @param workQueue       用于存放任务的阻塞队列
 * @param threadFactory   线程工厂类
 * @param handler         当队列和最大线程池都满了之后的饱和策略
 */
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

线程池可选择的阻塞队列

  • 无界队列
  • 有界队列 如果超出界定值,将阻塞 put 方法
  • 同步移交队列 也就是队列不存储元素,每个插入操作都要等待另一个线程调用移出操作,否则插入操作一直处于阻塞

无界队列

ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>();
for (int i = 0; i < 10; i++) {
  queue.put(i);
  System.out.println("向队列中添加值:" + i);
}
LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
for (int i = 0; i < 10; i++) {
  queue.put(i);
  System.out.println("向队列中添加值:" + i);
}

有界队列

ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);
for (int i = 0; i < 10; i++) {
  queue.put(i);
  System.out.println("向队列中添加值:" + i);
}
LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(5);
for (int i = 0; i < 10; i++) {
  queue.put(i);
  System.out.println("向队列中添加值:" + i);
}

同步移交队列

SynchronousQueue<Integer> queue = new SynchronousQueue<>();
for (int i = 0; i < 10; i++) {
  // 阻塞在这里
  queue.put(i);
  System.out.println("向队列中添加值:" + i);
}
SynchronousQueue<Integer> queue = new SynchronousQueue<>();
// 插入值
new Thread(() -> {
  try {
    queue.put(1);
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
}).start();
// 取值
new Thread(() -> {
  try {
    Integer value = queue.take();
    System.out.println("取到值:" + value);
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
}).start();

线程池可选择的饱和策略

说明
AbortPolicy 丢弃任务并抛出RejectedExecutionException异常 《默认》
DiscardPolicy 抛弃策略,但是不抛出异常
DiscardOldestPolicy 丢弃队列最前面的任务(旧任务),然后重新尝试执行任务
CallerRunsPolicy 由调用线程处理该任务

常用线程池

线程数量无限的线程池

ExecutorService pool = Executors.newCachedThreadPool();
public class Executors {
	public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
	}
}

线程数量固定线程池

ExecutorService pool = Executors.newFixedThreadPool(5);
public static ExecutorService newFixedThreadPool(int nThreads) {
  return new ThreadPoolExecutor(nThreads, nThreads,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>());
}

单一线程线程池

ExecutorService pool = Executors.newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor() {
  return new FinalizableDelegatedExecutorService
    (new ThreadPoolExecutor(1, 1,
                            0L, TimeUnit.MILLISECONDS,
                            new LinkedBlockingQueue<Runnable>()));
}

提交任务

submit,获取结果

ExecutorService threadPool = Executors.newCachedThreadPool();
// 提交任务,并获取结构
Future<Integer> future = threadPool.submit(() -> {
  Thread.sleep(3000L);
  return 2 * 5;
});
// 阻塞获取结果
Integer value = future.get();
System.out.println("执行结果:" + value);

execute,没有结果

ExecutorService threadPool = Executors.newCachedThreadPool();
threadPool.execute(() -> {
  try {
    Thread.sleep(1000L);
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
  // 计算结果
  Integer num = 2 * 3;
  System.out.println("执行结果:" + num);
});

线程池的状态

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章