线程池 的一些事

简介: 线程池 的一些事

0f11c8b5e6424e769f9e23f7a355fe49.jpg


一、线程池

1. 线程池的好处?


创建线程:线程的本质是PCB,是内核中的数据结构。而创建线程,由内核完成 PCB 的创建,把PCB加入到调度队列中~~然后再返回给应用程序。


而加入线程池:从线程池中去线程,把线程放回到线程池,这是纯用户态实现的逻辑。


创建线程需要涉及到 用户态~内核态 之间的切换,而这种切换存在很大的开销。为了避免这种情况,引入了线程池,实现了 纯用户态 的逻辑。


1. ThreadPoolExecutor 和 Executor ?


在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用 Executor 去创建,而要通过 ThreadPoolExecutor 方式,这一方面是由于 jdk 中  Executor  框架虽然提供了如newFixedThreadPool()、newSingleThreadExecutor()、newCachedThreadPool()等创建线程池的方法,但都有其局限性,不够灵活;另外由于前面几种方法内部也是通过ThreadPoolExecutor 方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险。


c5e502c33a80452a981722f947d14fa5.png

Executor 类 本质上是ThreadPoolExecutor 类 的封装

说白了,使用 Executor 类创建线程池与使用ThreadPoolExecutor类的区别就是使用 ThreadPoolExecutor 类可以自定义传入我们设置的线程池的参数,更加灵活。


二、构造方法:

1. ThreadPoolExecutor提供了四个构造方法:


79c45f3cd6f3496a9028672cd4932d89.png


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");
            }
        });
    }
}


相关文章
|
缓存 Java 应用服务中间件
线程池的10个坑你都遇到过吗
日常开发中,为了更好管理线程资源,减少创建线程和销毁线程的资源损耗,我们会使用线程池来执行一些异步任务。但是线程池使用不当,就可能会引发生产事故。大家看完肯定会有帮助的~
245 0
|
7月前
|
缓存 Java
|
3月前
|
监控 Java API
如何快速地实现一个线程池
如何快速地实现一个线程池
27 0
|
4月前
|
Java 调度
基于C++11的线程池
基于C++11的线程池
|
5月前
|
缓存 Java
线程池使用小结
线程池使用小结
29 0
|
7月前
|
缓存 Java API
厉害了,线程池就该这么玩
厉害了,线程池就该这么玩
65 0
|
7月前
|
Java C++
c++简单线程池实现
c++简单线程池实现
|
Java
6. 实现简单的线程池
6. 实现简单的线程池
58 0
KeyAffinityExecutor 线程池
KeyAffinityExecutor 线程池
|
消息中间件 监控 搜索推荐
线程池:我是谁?我在哪儿?
大家好,这篇文章跟大家探讨下日常使用线程池的各种姿势,重点介绍怎么在 Spring 环境中正确使用线程池。
314 1
线程池:我是谁?我在哪儿?