线程池ThreadPoolExecutor,阻塞队列 (实现BlockingQueue接口的队列)(gold_axe)

老马说编程

ThreadPoolExecutor实现了生产者/消费者模式,
任务队列:线程池自己维护
消费者:线程池的工作者线程
生产者: 任务提交者
当我们碰到类似生产者/消费者问题时,应该优先考虑直接使用线程池,

Java并发包中 线程池的实现类是ThreadPoolExecutor

↑它继承自AbstractExecutorService,实现了ExecutorService,是一个任务执行器

主要好处: 节约线程创建销毁的时间

2 更快开始
3 统一管理

构造方法& 主要参数

public ThreadPoolExecutor(
//控制线程池中线程的个数
                          int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
//任务队列
                          BlockingQueue<Runnable> workQueue)

//不怎么用  ThreadFactory RejectedExecutionHandler  一般用默认值
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
//对创建的线程进行一些配置
                          ThreadFactory threadFactory,
//拒绝策略
                          RejectedExecutionHandler handler) 

线程池大小& 执行流程

线程池的大小主要与四个参数有关:

  • corePoolSize
    有新任务到来的时候,如果当前线程个数小于corePoolSiz,就会创建一个新线程来执行该任务,需要说明的是,即使其他线程现在也是空闲的,也会创建新线程。
    不过,如果线程个数大于等于corePoolSiz,那就不会立即创建新线程了,它会先尝试排队

数量建议: IO等待多的, 核心线程数可以设大点
计算密集型的:cpu+1
IO密集型的:cpu2
公式:Ncpu
(1+等待时间)/总时间

  • maximumPoolSize
    最大值,不管有多少任务,都不会创建比这个值大的线程个数。
    如果队列满了或其他原因不能立即入队,会继续创建线程,直到线程数达到maximumPoolSize。

  • keepAliveTime
    线程个数大于corePoolSize时,
    非核心线程,最长等待时间,
    如果该值为0,表示所有线程都不会超时终止。

这几个参数除了可以在构造方法中进行指定外,还可以通过getter/setter方法进行查看和修改。

除了这些静态参数,ThreadPoolExecutor还可以查看关于线程和任务数的一些动态数字:
//返回当前线程个数
public int getPoolSize()
//返回线程池曾经达到过的最大线程个数
public int getLargestPoolSize()
//返回线程池自创建以来所有已完成的任务数
public long getCompletedTaskCount()
//返回所有任务数,包括所有已完成的加上所有排队待执行的
public long getTaskCount()

等待队列

只要是是阻塞队列 (实现BlockingQueue接口的队列)都行
队列

jdk文档 ThreadPoolExecutor举例也是这3个

比如:

  • LinkedBlockingQueue:基于链表,可以指定最大长度,默认是无界的, 传了参数可以有界
  • PriorityBlockingQueue:基于堆,无界,优先

无界:线程个数最多只能达到corePoolSize,队列永远不会满,,新的任务总会排队,参数maximumPoolSize无效

  • ArrayBlockingQueue:基于数组,有界
  • SynchronousQueue:没有实际存储空间

没有实际存储空间: 就是队列里一个都没得存,
当尝试排队时,只有正好有空闲线程在等待接受任务时,才会入队成功,
否则,总是会创建新线程,直到达到maximumPoolSize。

如何创造一个线程

构造参数ThreadFactory,它是一个接口:

public interface ThreadFactory {
    Thread newThread(Runnable r);
}

这个接口根据Runnable创建一个Thread,
一般不自己弄,用默认的
默认实现是Executors类中的静态内部DefaultThreadFactory,
主要就是创建一个线程,给线程设置一个名称( pool-<线程池编号>-thread-<线程编号>),设置daemon属性为false,设置线程优先级为标准默认优先级。

如果排队满了,线程也达到最大,怎么办?任务拒绝策略

是一个限流的思想, 防止全线崩溃, 一般可以自定义加点日志,
如果关闭了还来提交任务, 也是会用拒绝策略

默认情况下,抛出异常,类型为RejectedExecutionException

拒绝策略是可以自定义的(构造参数RejectedExecutionHandler ),
RejectedExecutionHandler接口,这个接口的定义为:

public interface RejectedExecutionHandler {
    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

ThreadPoolExecutor实现了四种处理方式:

  • ThreadPoolExecutor.AbortPolicy:这就是默认的方式,抛出异常
    private static final RejectedExecutionHandler defaultHandler =new AbortPolicy();
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    throw new RejectedExecutionException("Task " + r.toString() +
                                         " rejected from " +
                                         e.toString());
}
  • ThreadPoolExecutor.DiscardPolicy:静默处理,忽略新任务,不抛异常,也不执行

  • ThreadPoolExecutor.DiscardOldestPolicy:将等待时间最长的任务扔掉,然后自己排队

  • ThreadPoolExecutor.CallerRunsPolicy:在任务提交者线程中执行任务,而不是交给线程池中的线程执行

而AbortPolicy的rejectedExecution实现就是抛出异常,如下所示:

拒绝策略只有在队列有界,且maximumPoolSize有限的情况下才会触发。
如果队列无界,服务不了的任务总是会排队,请求处理队列可能会消耗非常大的内存,甚至引发内存不够的异常。
如果队列有界但maximumPoolSize无限,可能会创建过多的线程,占满CPU和内存,使得任何任务都难以完成。
所以,在任务量非常大的场景中,让拒绝策略有机会执行是保证系统稳定运行很重要的方面。

注意: 依赖关系任务提交同一个线程,可能死锁

如下,任务A被提交到线程池,任务A里面提交了任务B到同个线程池,要等B完成才往下走,但是任务B可能在线程池里面排队,等A任务完成

//里面是有界队列 
static ExecutorService executor = Executors.newFixedThreadPool(5);

    static class TaskA implements Runnable {
        @Override
        public void run() {
            
            //其他事
            //Thread.sleep(100);
            Future<?> future = executor.submit(new TaskB());
            try {
                future.get();//要任务B完成才能完成 可能任务B在排队等A完成
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }

            System.out.println("finished task A");
        }
    }

线程池终止

都是会改变线程池的状态,:

  • shutdown 优雅关闭, 一般是用这个, 只是不让提交新的, 已经提交的执行完
  • shutdownNow

后者, 连队列里面都不做了, 正进行的线程也尽力阻止,
尽力是说interrupt, 至于任务是不是会响应就不一定了, 也可能不响应, 还是执行完

unable to create new native thread

线程总数超过操作系统限制了

  1. 是不是真的要那么多线程?线程太多了, 小一点
  2. 加机器
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,172评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,346评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,788评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,299评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,409评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,467评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,476评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,262评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,699评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,994评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,167评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,499评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,149评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,387评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,028评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,055评论 2 352

推荐阅读更多精彩内容