1. 1 不可撤销
  2. 2 小年兽 程嘉敏
  3. 3 手放开 李圣杰
  4. 4 迷人的危险3(翻自 dance flow) FAFA
  5. 5 山楂树之恋 程佳佳
  6. 6 summertime cinnamons / evening cinema
  7. 7 不谓侠(Cover 萧忆情Alex) CRITTY
  8. 8 神武醉相思(翻自 优我女团) 双笙
  9. 9 空山新雨后 音阙诗听 / 锦零
  10. 10 Wonderful U (Demo Version) AGA
  11. 11 广寒宫 丸子呦
  12. 12 陪我看日出 回音哥
  13. 13 春夏秋冬的你 王宇良
  14. 14 世界が终わるまでは… WANDS
  15. 15 多想在平庸的生活拥抱你 隔壁老樊
  16. 16 千禧 徐秉龙
  17. 17 我的一个道姑朋友 双笙
  18. 18 大鱼  (Cover 周深) 双笙
  19. 19 霜雪千年(Cover 洛天依 / 乐正绫) 双笙 / 封茗囧菌
  20. 20 云烟成雨(翻自 房东的猫) 周玥
  21. 21 情深深雨濛濛 杨胖雨
  22. 22 Five Hundred Miles Justin Timberlake / Carey Mulligan / Stark Sands
  23. 23 斑马斑马 房东的猫
  24. 24 See You Again Wiz Khalifa / Charlie Puth
  25. 25 Faded Alan Walker / Iselin Solheim
  26. 26 Natural J.Fla
  27. 27 New Soul Vox Angeli
  28. 28 ハレハレヤ(朗朗晴天)(翻自 v flower) 猫瑾
  29. 29 像鱼 王贰浪
  30. 30 Bye Bye Bye Lovestoned
  31. 31 Blame You 眠 / Lopu$
  32. 32 Believer J.Fla
  33. 33 书信 戴羽彤
  34. 34 柴 鱼 の c a l l i n g【已售】 幸子小姐拜托了
  35. 35 夜空中最亮的星(翻自 逃跑计划) 戴羽彤
  36. 36 慢慢喜欢你 LIve版(翻自 莫文蔚) 戴羽彤
  37. 37 病变(翻自 cubi) 戴羽彤
  38. 38 那女孩对我说 (完整版) Uu
  39. 39 绿色 陈雪凝
  40. 40 月牙湾 LIve版(翻自 F.I.R.) 戴羽彤
夜空中最亮的星(翻自 逃跑计划) - 戴羽彤
00:00 / 04:10

夜空中最亮的星 能否听清

那仰望的人 心底的孤独和叹息

夜空中最亮的星 能否记起

那曾与我同行 消失在风里的身影

我祈祷拥有一颗透明的心灵

和会流泪的眼睛

给我再去相信的勇气

越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请指引我靠近你

夜空中最亮的星 是否知道

那曾与我同行的身影 如今在哪里

夜空中最亮的星 是否在意

是等太阳先升起 还是意外先来临

我宁愿所有痛苦都留在心底

也不愿忘记你的眼睛

哦 给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行 哒~

我祈祷拥有一颗透明的心灵

和会流泪的眼睛 哦

给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行

多线程之线程池 · 下

前言

线程池中这块的内容确实要比我预期的多,当然也可能是我讲的太细了,所以比较费字,但是这样也好,不仅让各位小伙伴能更清楚相关逻辑和原理,而且对我而言,让我可以做到知其然知其所以然,从这个层面上来讲,我觉得一切都值得,甚至还有点意外的收获。

今天是线程池相关知识点收官之作,今天的内容完结后,基本上线程池这块的内容就可以告一段落了,今天主要从以下几方面开展:

  • 线程池的其他参数
    • 线程工厂
    • 拒绝策略处理器

好了,话不多说,让我们直接开始吧。

线程池

线程工厂

先看第一个参数——线程工厂,这个参数的作用是创建线程。在最开始的时候,我们创建线程池的时候并没有指定这个参数,但是构造器内部会自动为我们引入默认的线程工厂:

下面我们就来看下默认的线程工厂是如何实现的:

在线程工厂中,主要有两部分的操作,第一部分就是设定创建线程时的信息,包括线程组、线程名称、堆栈大小;第二部分主要是设置线程的优先级,如果线程是守护线程的话,会把它修改为非守护线程(看到这里,我发现关于线程组、线程得好好补补课了,后面要跟进下)。

我们一般自定义线程工厂主要是为了修改线程名称,这样方便我们在排查问题的时候找到我们自己定义的线程池,我们要自顶一下线程工厂只需要冲洗ThreadFactorynewThread方法即可:

static class MyThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        MyThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                    Thread.currentThread().getThreadGroup();
            namePrefix = "syske-" +
                    poolNumber.getAndIncrement() +
                    "-thread-";
        }

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                    namePrefix + threadNumber.getAndIncrement(),
                    0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

这里我就直接把默认线程工厂的实现copy过来,然后只改了名字,然后在构造线程池的时候传入即可:

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new MyThreadFactory());

然后运行下,我们就会发现线程名称已经变成我们修改之后的了:

当然如果只是单纯想修改线程池中线程名称,这样就太奢侈了,我们可以通过guava提供的ThreadFactoryBuilder直接修改(就是我们之前分享的guava):

ThreadFactory build = new ThreadFactoryBuilder().setNameFormat("syske-task-%d").build();

当然,guava还可以设定其他属性,甚至可以指定线程工厂,UncaughtExceptionHandler表示未捕获到的异常处理器:

拒绝策略(饱和策略)

我们在之前的内容中说过,如果任务数超过corePoolSize + maximumPoolSize + workQueue.size(),线程池就会报拒绝连接的错误,这个错误就是这里抛出了的,所以接下来我们要分享的就是线程池的最后一个参数——RejectedExecutionHandler

和线程工厂一样,在我们不传拒绝策略处理器的时候,其实构造方法内部为我们制定了默认的处理器:

默认拒绝策略处理器的实现也很简单:

也可以说是简单粗暴,直接就抛出了RejectedExecutionException异常。

当然我们也可以定义自己的拒绝策略处理器:

 static class MyRejectedExecutionHandler implements RejectedExecutionHandler {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            System.out.println("线程池拒绝连接,资源已耗尽:r = " + r + ", executor = " + executor);
            throw new RejectedExecutionException();
        }
    }

然后也是在构造线程池的时候传入:

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new MyThreadFactory(), new MyRejectedExecutionHandler());

我们把工作对了调小,把循环次数调大,把休眠时间调长,然后运行就会触发饱和策略,进入我们的的rejectedExecution方法:

根据我的测试,我发现如果在rejectedExecution方法中直接抛出RejectedExecutionException,会导致主线程进入阻塞状态,这样整个系统就卡死了

但如果不抛出RejectedExecutionException异常的话,则不会导致阻塞:

所以考虑到实际应用情况,我觉得我们还是有必要重写rejectedExecution方法的,而且我们在方法内部还可以做一些业务操作,比如线程池扩容,或者睡眠等待:

或者可以做一些业务告警等操作。

总结

关于线程池的创建、参数以及参数的作用,经过我们这两天的详细分析和演示,我想大家一定也对线程池有了新的认知,应该说在以后的工作和学习中,不论是线程池的使用还是解决线程池相关的问题,都可以站得更高,看的更远。

当然,最重要的是,这几天分享的内容都比较实用。明天我们会对线程池这块做一个小结,然后小结之外我们会有一些遗漏知识点的补充。好了,今天就先到这里吧!

posted @ 2021-07-17 16:55  云中志  阅读(55)  评论(0编辑  收藏  举报