多线程2

文章最后更新时间:2025年05月16日

猜测一下,打印的“线程测试”的两个方法 那个是多线程执行的?

/**
 * @author : zanglikun
 * @date : 2021/12/31 15:25
 * @Version: 1.0
 * @Desc : 继承Thread 重写run方法
 */public class ThreadDemo extends Thread{@Overridepublic void run() {
        System.out.println("线程测试");
    }public static void main(String[] args) {new ThreadDemo().run();new ThreadDemo().start();
    }
}

答案是 start()执行的是多线程的。

我们Debug看一下:

run()方法

image.png

进入断点之后点击 照相机(获取线程转储) 就可以看到当前项目的线程信息了!

image.png

Start()方法

image.png

对比一下,run方法的线程名叫mainstart方法执行的线程名是 Thread-0@509

在对比一下 单线程与多线程的执行效率

单线程代码

    @SneakyThrows@Testpublic void testSingleThread() {long StartTime = System.currentTimeMillis();final ArrayList<String> arrayList = new ArrayList();for (int i = 0; i < 100000; i++) {Thread thread = new Thread() {@Overridepublic void run() {
                    arrayList.add("abcdfg");
                }
            };
            thread.start();// join()让Thread这个线程 在main线程结束时等待,让其在main线程结束后在结束!thread.join();
        }long EndTime = System.currentTimeMillis();
        System.out.println("消耗了:" + (EndTime - StartTime) / 1000.00 + "秒");
        System.out.println(arrayList.size());
    }
消耗了:25.095秒100000

多线程代码

    @SneakyThrows@Testpublic void testMuiltThread() {long StartTime = System.currentTimeMillis();final ArrayList<String> arrayList = new ArrayList();ExecutorService executorService = Executors.newSingleThreadExecutor();for (int i = 0; i < 100000; i++) {
            executorService.execute(() -> {
                arrayList.add("abcdfg");
            });
        }// 如果不shutdown,那么main方法走完了,直接打印消耗时间、打印集合长度时不准确的。因为main线程结束,线程池的线程还在执行,就打印结果肯定是不准确的executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.DAYS);long EndTime = System.currentTimeMillis();
        System.out.println("消耗了:" + (EndTime - StartTime) / 1000.00 + "秒");
        System.out.println(arrayList.size());
    }
消耗了:0.05秒100000

测试不同线程池的效率

    @SneakyThrows@Testpublic void testDifferentThreadPool() {long StartTime = System.currentTimeMillis();final ArrayList<String> arrayList = new ArrayList();ExecutorService executorService1 = Executors.newCachedThreadPool(); //最快ExecutorService executorService2 = Executors.newFixedThreadPool(10); //慢大约49倍的执行时间(只在本场景(循环1000次)适用,不是两个线程池的的规范的效率差距)ExecutorService executorService3 = Executors.newSingleThreadExecutor(); //对比上一个慢了10倍(只在本场景(循环1000次)适用,不是两个线程池的的规范的效率差距)for (int i = 0; i < 1000; i++) {
            executorService1.execute(() -> {try {
                    System.out.println("当前线程名称"+Thread.currentThread().getName());
                    arrayList.add("abcdef");
                    Thread.sleep(500L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }// 如果不shutdown,那么main方法走完了,直接打印消耗时间、打印集合长度时不准确的。因为main线程结束,线程池的线程还在执行,就打印结果肯定是不准确的executorService1.shutdown();
        executorService1.awaitTermination(1, TimeUnit.DAYS);long EndTime = System.currentTimeMillis();
        System.out.println("消耗了:" + (EndTime - StartTime) / 1000.00 + "秒");
        System.out.println(arrayList.size());
    }

使用不同线程池分别执行一下,结果:

newCachedThreadPool() 0.616秒
打印日志如下:
当前线程名称pool-1-thread-1
当前线程名称pool-1-thread-3
当前线程名称pool-1-thread-2
......
当前线程名称pool-1-thread-997
当前线程名称pool-1-thread-998
当前线程名称pool-1-thread-999
当前线程名称pool-1-thread-1000
... 线程ID 编号取值1-1000



newFixedThreadPool() 50.037秒
打印日志如下:
当前线程名称pool-2-thread-1
当前线程名称pool-2-thread-2
当前线程名称pool-2-thread-3
当前线程名称pool-2-thread-4
当前线程名称pool-2-thread-6
当前线程名称pool-2-thread-5
当前线程名称pool-2-thread-7
当前线程名称pool-2-thread-8
当前线程名称pool-2-thread-10
当前线程名称pool-2-thread-9
... 以此循环线程ID 编号取值1-10  这里就能看到线程复用的提现!




newSingleThreadExecutor() 我预测是500秒,没想到还真是500.306秒
打印日志如下:
当前线程名称pool-3-thread-1
当前线程名称pool-3-thread-1
当前线程名称pool-3-thread-1
... 线程ID 编号取值都是1

三种线程池为什么有这么大的差距?

分别看一下这三种线程池源码的构造方法

    public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE, #MAX_VALUE是 
                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue<Runnable>());
    }public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue<Runnable>());
    }public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
    }

构造方法里核心线程数、最大线程数,也就是前2个参数区别(阻塞队列这里我们忽略不考虑)!造成了这个场景的效率差距!

newCachedThreadPool 最大允许开启21亿个线程处理任务


newFixedThreadPool 最大允许开启10个线程处理(我们上方创建对象传入的10)


newSingleThreadExecutor 最大允许开启1个线程处理任务

所以 对应的结果日志时间上的比例也是如此了
第一次 线程直接处理完毕了,而第二次同期时间才处理了10个 剩余990任务都是阻塞的,所以第一次比第二次早了 990 *0.5睡眠的时间 也就是大约48.5秒
第二次 比第三次线程也多了10倍 所以第二次比第三次消耗的时间的10倍。
<div style="height:100px" ari

文章版权声明:除非注明,否则均为八一构原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
AddoilApplauseBadlaughBombCoffeeFabulousFacepalmFecesFrownHeyhaInsidiousKeepFightingNoProbPigHeadShockedSinistersmileSlapSocialSweatTolaughWatermelonWittyWowYeahYellowdog
评论列表 (暂无评论,71人围观)

还没有评论,来说两句吧...

目录[+]

取消
微信二维码
微信二维码
支付宝二维码