• Java并发线程池原理源码深入分析与调优实战


    一,开篇:

            java中提供了多线程设计的Api,为什么还要用线程池呢?

            下来看两个例子:

                    1.  使用多线程跑十万次

                    2.  使用线程池跑十万次

    使用多线程跑十万次

    1. package com.laoyang.ThreadPool.公开课;
    2. import java.util.ArrayList;
    3. import java.util.Random;
    4. /**
    5. * @author:Kevin
    6. * @create: 2023-10-25 18:27
    7. * @Description: 多线程跑十万次代码测试
    8. */
    9. public class ThreadDemo {
    10. public static void main(String[] args) throws InterruptedException {
    11. long currentTimeMillis = System.currentTimeMillis();
    12. Random random = new Random();
    13. ArrayList list = new ArrayList<>();
    14. for (int i = 0; i < 100000; i++) {
    15. Thread thread = new Thread() {
    16. @Override
    17. public void run() {
    18. list.add(random.nextInt(10));
    19. }
    20. };
    21. thread.start();
    22. thread.join();
    23. }
    24. System.out.println("时间:" + (System.currentTimeMillis() - currentTimeMillis));
    25. System.out.println("大小:" + list.size());
    26. }
    27. }

    运行结果:

    使用线程池跑十万次

    1. package com.laoyang.ThreadPool.公开课;
    2. import java.util.ArrayList;
    3. import java.util.Random;
    4. import java.util.concurrent.Executor;
    5. import java.util.concurrent.ExecutorService;
    6. import java.util.concurrent.Executors;
    7. import java.util.concurrent.TimeUnit;
    8. /**
    9. * @author:Kevin
    10. * @create: 2023-10-25 18:28
    11. * @Description: 多线程跑十万次测试
    12. */
    13. public class ThraedPollDemo {
    14. public static void main(String[] args) throws InterruptedException {
    15. long currentTimeMillis = System.currentTimeMillis();
    16. Random random = new Random();
    17. ArrayList list = new ArrayList<>();
    18. ExecutorService executor = Executors.newSingleThreadExecutor();
    19. for (int i = 0; i < 100000; i++) {
    20. executor.execute(new Runnable() {
    21. @Override
    22. public void run() {
    23. list.add(random.nextInt(10));
    24. }
    25. });
    26. }
    27. executor.shutdown();
    28. executor.awaitTermination(1, TimeUnit.DAYS);
    29. System.out.println("时间:" + (System.currentTimeMillis() - currentTimeMillis));
    30. System.out.println("大小:" + list.size());
    31. }
    32. }

    运行结果:

            可以看出两者简直天壤地别!!!

           

            两者区别:

                    1. 第一种创建了100001个线程,但是第二种只创建了两个线程

            为什么?

            创建的线程越多,是对还是错?  肯定是错的

            线程池的好处与不足?(OOM内存溢出,cpu-100%)

            底层原理?

            那为什么阿里巴巴又不推荐使用java自带的线程池呢?
           

     二,线程池

    1. 初次认识常见的线程池三种方式

    1. package com.laoyang.ThreadPool.公开课;
    2. import java.util.concurrent.Executor;
    3. import java.util.concurrent.ExecutorService;
    4. import java.util.concurrent.Executors;
    5. /**
    6. * @author:Kevin
    7. * @create: 2023-10-25 18:50
    8. * @Description: 初次认识线程池的几个构建方式
    9. */
    10. public class ThreadPoolMainTest {
    11. public static void main(String[] args) {
    12. ExecutorService executorService2 = Executors.newCachedThreadPool(); //快
    13. ExecutorService executorService3 = Executors.newFixedThreadPool(10); //中
    14. ExecutorService executorService1 = Executors.newSingleThreadExecutor(); //慢
    15. for (int i = 0; i < 100; i++) {
    16. executorService2.execute(new Mytest(i));
    17. }
    18. }
    19. }
    20. class Mytest implements Runnable{
    21. private int i = 0;
    22. public Mytest(int i) {
    23. this.i = i;
    24. }
    25. @Override
    26. public void run() {
    27. System.out.println(String.format(Thread.currentThread().getName()+ "当前开始第 %s 个项目", i));
    28. try {
    29. Thread.sleep(1000L);
    30. }catch (Exception e){}
    31. }
    32. }

        可以发现执行速度从快到最慢

        速度: newCachedThreadPool > newFixedThreadPool > newSingleThreadExecutor

            假如将线程休眠代码注释,就会出现线程复用!

    2. 剖析源码

            newCachedThreadPool点进去一个就是ThreadPoolExecutor,那么现在来深度剖析下参数的每个意思。

            SynchronousQueue:同步队列(同步机制)

            可以发现只有非核心线程数,就是有一个任务,来一个非核心员工

            newFixedThreadPool点进去也是ThreadPoolExecutor

            可以发现核心线程数与最大线程数的值是一样的,说明只有核心线程数,没有额外的线程数

            newSingleThreadExecutor点进去也是ThreadPoolExecutor

            这个参数说明只创建了一个线程对象,个体户

           3. 自定义线程池

    1. ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 20,
    2. 10L, TimeUnit.SECONDS, new ArrayBlockingQueue(10));

            如果自定义的话会抛出异常,会在第31个抛出异常。原因:核心线程数10,最大线程数20,所以非核心线程数将是10个,同时阻塞队列大小为10,所以当阻塞队列慢的时候就会抛出异常。

            那为什么执行的顺序为什么不一样,应该是1-10,11-20,21-30,但结果确相反?

            原理:优先级  (核心线程>非核心线程>队列线程)

  • 相关阅读:
    【音视频笔记】Mediacodec+Muxer生成mp4,浏览器无法播放问题处理
    C++ Qt开发:QHostInfo主机地址查询组件
    系列五、线程间通信
    c: Queue Calling in Ubuntu
    【能效管理】电力监控系统在移动某分公司配电系统中的应用分析
    MybatisPlus 处理保存实体对象时,对于枚举类型的数据库存储问题
    蜂窝物联网咖WiFi认证解决方案
    Semtech GS2971AIBE3 3G SDI 接收器
    网络安全-端口信息收集
    Blazor前后端框架Known功能介绍:系统安装激活及自定义
  • 原文地址:https://blog.csdn.net/qq_67801847/article/details/134041017