一、线程池
1. 线程池的好处?
创建线程:线程的本质是PCB,是内核中的数据结构。而创建线程,由内核完成 PCB 的创建,把PCB加入到调度队列中~~然后再返回给应用程序。
而加入线程池:从线程池中去线程,把线程放回到线程池,这是纯用户态实现的逻辑。
创建线程需要涉及到 用户态~内核态 之间的切换,而这种切换存在很大的开销。为了避免这种情况,引入了线程池,实现了 纯用户态 的逻辑。
1. ThreadPoolExecutor 和 Executor ?
在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用 Executor 去创建,而要通过 ThreadPoolExecutor 方式,这一方面是由于 jdk 中 Executor 框架虽然提供了如newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPool()等创建线程池的方法,但都有其局限性,不够灵活;另外由于前面几种方法内部也是通过ThreadPoolExecutor 方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险。
Executor 类 本质上是ThreadPoolExecutor 类 的封装
说白了,使用 Executor 类创建线程池与使用ThreadPoolExecutor类的区别就是使用 ThreadPoolExecutor 类可以自定义传入我们设置的线程池的参数,更加灵活。
二、构造方法:
1. ThreadPoolExecutor提供了四个构造方法:
2. 构造参数解释:
序号 | 名称 | 类型 | 含义 |
1 | corePoolSize | int | 核心线程池大小 |
2 | maximumPoolSize | int | 最大线程池大小 |
3 | keepAliveTime | long | 线程最大空闲时间 |
4 | unit | TimeUnit | 时间单位 |
5 | workQueue | BlockingQueue<Runnable> | 线程等待队列 |
6 | threadFactory | ThreadFactory | 线程创建工厂 |
7 | handler | RejectedExecutionHandler | 拒绝策略 |
3. 线程池的执行流程
① 当加入一个新任务时,判断 当前线程数 > 核心线程数 ? 如果false,则新建线程并且执行任务。
② 如果true,则判断 任务队列是否满了? 如果false,则放到任务队列,等待核心线程处理。
③ 如果true,则判断 当前线程数>最大线程数? 如果false 则新建线程执行此任务。
④ 如果true,则执行拒绝策略
4. 几种拒绝策略
AbortPolicy -- 抛出 RejectedExecutionException 异常。
CallerRunsPolicy -- 让调用者处理
DiscardOldestPolicy -- 丢弃最老的任务,将新任务放到等待队列。
DiscardPolicy -- 直接丢弃这个新任务
5. 由于参数过于复杂,我们可以通过Executors的工厂方法创建线程池
newFixedThreadPool :创建固定线程数的线程池
CachedThreadPool:创建线程数媒动态增长的线程池
SingleThreadExecutor:创建只包含单个线程的线程池
ScheduledThreadPool:设定 延迟时间后执行命令,或定期执行命令,是进阶版的 Timer
public static void main(String[] args) { //创建一个固定有10个线程数的线程池 ExecutorService executorService = Executors.newFixedThreadPool(10); Runnable run = new Runnable() { @Override public void run() { System.out.println("good !"); } }; executorService.submit(run); }
三、代码简单实现
核心操作是 submit --- 将任务加入到线程池中
使用 Worker 类描述一个工作线程,使用 Runnable 或者 Callable 描述一个任务
使用一个 BlockingQueue 组织所有任务
每个Worker 县城要做的事情:不停的从 BlockingQueue 中取任务并执行
指定一下线程池中最大线程数 maxWorkerCount ,当当前线程数超过这个最大值就不再新增线程
import java.util.LinkedList; import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; public class Demo10 { //MyWork 负责完成组织一个线程的工作 public static class MyWork extends Thread { private LinkedBlockingQueue<Runnable> queue; public MyWork(LinkedBlockingQueue<Runnable> queue) { super(); this.queue = queue; } @Override public void run() { try { while (!Thread.interrupted()){ Runnable runnable = queue.take(); runnable.run(); } } catch (InterruptedException e) { throw new RuntimeException(e); } } } //Study.MyThreadPool 负责完成组织所有的线程 public static class MyThreadPool { private int maxContain = 10;//最多开辟多少个线程 private LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(); private List<MyWork> workList = new LinkedList<>(); public void submit(Runnable runnable) throws InterruptedException { if (maxContain > queue.size()) {//如果线程数量没有达到最大则优先创建一个新线程执行任务 MyWork work = new MyWork(queue); workList.add(work); work.start(); } queue.put(runnable); } } public static void main(String[] args) throws InterruptedException { MyThreadPool pool = new MyThreadPool(); pool.submit(new Runnable() { @Override public void run() { System.out.println("111"); } }); } }