­

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

  • 2019 年 10 月 10 日
  • 筆記

学习多线程的时候,我们都知道如果多个线程分配到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