专栏首页Java研发军团多线程真的会使用CPU所有的内核吗?

多线程真的会使用CPU所有的内核吗?

学习多线程的时候,我们都知道如果多个线程分配到CPU多个内核是可以并发的执行。但真的是这样的吗?

先来看看电脑配置:

测试电脑是单CPU,4核。按道理来说创建4个线程应该可以分配到4个内核同时执行。接下来执行测试代码看结果!

public class ThreadTest {

    private static final int num = 1000 * 1000;

    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            for (int i = 0; i < num; i++) {
                System.out.println(i);
            }
        },"线程1").start();

        new Thread(()->{
            for (int i = 0; i < num; i++) {
                System.out.println(i);
            }
        },"线程2").start();

        new Thread(()->{
            for (int i = 0; i < num; i++) {
                System.out.println(i);
            }
        },"线程3").start();

        new Thread(()->{
            for (int i = 0; i < num; i++) {
                System.out.println(i);
            }
        },"线程4").start();
    }
}

测试代码创建了四个线程,四个线程都遍历一百万次。通过使用JDK自带监控工具:Visual VM 查看线程的执行过程,是不是真的如我想象,并发的执行线程呢?

关注红色框的内容,惊奇的发现,多个线程根本没有并发执行,而是不断的在线程之间上下文切换!也就是说,4个线程都是在单个内核执行,其他的内核并没有工作!

这就有点颠覆我的认知了,后来不断的google、查阅资料我才发现,这个与操作系统CPU的算法有关系!

参考文章:https://www.zhihu.com/question/64072646

线程的调度是根据cpu的算法,如果线程的运算量不大,cpu算法调度线程不一定会平均分配给每个内核的。那意思是如果运算量大的话,就会使用到其他的内核咯?

继续改进测试代码:

public class ThreadTest{

    // 数据量
    private static final int num = 2000 * 1000;

    // 设置栅栏是为了防止子线程还没结束就执行main线程输出耗时时间
    private static final CountDownLatch countDownLatch = new CountDownLatch(4);

    private static ExecutorService service = Executors.newFixedThreadPool(4);

    private static final String filePath1 = "/Users/hao/IdeaProjects/Sample/src/test1.txt";
    private static final String filePath2 = "/Users/hao/IdeaProjects/Sample/src/test2.txt";
    private static final String filePath3 = "/Users/hao/IdeaProjects/Sample/src/test3.txt";
    private static final String filePath4 = "/Users/hao/IdeaProjects/Sample/src/test4.txt";

    private static File file1 = new File(filePath1);
    private static File file2 = new File(filePath2);
    private static File file3 = new File(filePath3);
    private static File file4 = new File(filePath4);

    public static void main(String[] args) throws InterruptedException, IOException {
        // 开始时间
        long startTime = System.currentTimeMillis();

        new Thread(new WriteFileThread(file1),"线程1").start();
        new Thread(new WriteFileThread(file2),"线程2").start();
        new Thread(new WriteFileThread(file3),"线程3").start();
        new Thread(new WriteFileThread(file4),"线程4").start();

        try {
            countDownLatch.await();
        } finally {
            service.shutdown();
        }

        // 结束时间
        long endTime = System.currentTimeMillis();
        System.out.println();
        System.out.println("总耗时间为:" + (endTime - startTime) / 1000.0 + "s");

    }

    static class WriteFileThread implements Runnable {

        private File file;

        public WriteFileThread(File file) {
            this.file = file;
        }

        @Override
        public void run() {
            writeFile(file);
        }
    }

    static void writeFile(File file){
        // 判断是否有该文件
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        long startTime = System.currentTimeMillis();
        //创建输出缓冲流对象
        BufferedWriter bufferedWriter = null;
        try {
            bufferedWriter = new BufferedWriter(new FileWriter(file));
        } catch (IOException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < num; i++) {
            try {
                bufferedWriter.write(i);
                bufferedWriter.newLine();
                bufferedWriter.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println(Thread.currentThread().getName() + "执行完成,耗时 : " + (endTime - startTime) / 1000 + "s");
        countDownLatch.countDown();
        try {
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

输出结果:

线程4执行完成,耗时 : 22s
线程3执行完成,耗时 : 22s
线程1执行完成,耗时 : 22s
线程2执行完成,耗时 : 24s

总耗时间为:24.709s

再查看Visual VM 监控工具,可以发现,4个线程都并发的执行了!

END

本文分享自微信公众号 - Java研发军团(ityuancheng),作者:MuggleLee

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 初学者第66节生产者消费者(八)

    上一节讲解了生产者与消费者模式的基本理论以及简单实现,并且遗留下来一个消费商品是null,库存为:-1的问题 ,看下代码。

    用户5224393
  • 初学者第61节之线程停止详解(三)

    以上大家可以看出来了吧,其实就是在循环的条件上做手脚就好了,因为每次循环都会根据这个while条件来判断的,所以在开启线程之后休眠3秒之后在将while条件设置...

    用户5224393
  • 是程序员就不得不懂线程池的使用及扩展和优化!!!

    多线程的软件设计方法确实可以最大限度的发挥现代多核处理器的计算能力,提高生产系统的吞吐量和性能。

    用户5224393
  • 多线程真的会使用CPU所有的核吗?

    原文链接:http://www.jianshu.com/p/352caffd6366

    业余草
  • Netty框架研究

    jeremyxu
  • javascript 基本概念

    一、在HTML中使用javascript 1.直接是用<script></script>标签。 2.外部引入 <script type="javascript"...

    柴小智
  • Android的JNI【实战教程】6⃣️--温控计

    demo下载地址:http://download.csdn.net/detail/github_33304260/9860547

    先知先觉
  • 【面试宝典】static 关键字

    面试官:static关键字你了解吗?说一下你的认识。 小白:啊.....有点晕呀,这么宽泛的问题,我该从哪回答呢?头脑一片空白。让我想想...... 面试官:没...

    程序员互动联盟
  • python 对字典"排序"总结

    对字典进行排序?这其实是一个伪命题,搞清楚python字典的定义---字典本身默认以key的字符顺序输出显示---就像我们用的真实的字典一样,按照abcd字母的...

    用户5745385
  • .NET/C# 使窗口永不激活(No Activate 永不获得焦点)

    发布于 2018-07-24 06:19 更新于 2018-08...

    walterlv

扫码关注云+社区

领取腾讯云代金券