• 带你玩转java多线程系列 “道篇” 多线程的优势及利用util.concurrent包测试单核多核下多线程的效率


    java多线程 “道篇” - 多线程的优势及用concurrent包测试单核多核下多线程的效率
    1 超哥对于多线程自己的理解
    2 测试代码
    3 CountDownLatch这个同步辅助类科普
    4 如何把电脑设置成单核
    5 测试结果
     
    1 超哥对于多线程自己的理解
     
    超哥的理解:对于多线程,无非是对于顺序执行下任务的一种抽取和封装,将原来顺序执行的任务单独拿出来放到线程类的run方法中,通过线程类的start方法进行执行,对于多线程访问共同资源时,我们需要加锁,也就是只有某个线程在拥有锁的时候,才能够得到执行权利,超哥一想,坏了,这如果在单核的情况下,本来就只有一个核来执行任务,你倒好,弄个多线程,你让一个电脑内核还要不断的切换不同的线程执行任务,这得到锁,释放锁,切换的时间不就还没有顺序执行的效率高吗,所以超哥猜想只有在多核的条件下才能体现出多线程的效率高,在单核的情况下如果鼓捣个多线程那就是吃饱啦没事干。。。下面做实验验证超哥猜想
    实验:实验环境,电脑:惠普G42,CPU i3-390 ,内存 4G 超哥穷,没钱上好机器
    知识储备要求:熟悉java多线程,java concurrent包的基本使用
     
    2 测试代码
    import java.util.concurrent.CountDownLatch;  
    
     
    
    public class Test {  
    
     
    
        public static void main(String[] args) {  
    
            int num = 100000;  
    
            test1(num);  
    
            test2(num);  
    
        }  
    
     
    
        private static void test1(int max) {  
    
            long t1 = System.currentTimeMillis();  
    
            int n = method1(max);  
    
            long t2 = System.currentTimeMillis();  
    
            System.out.println("method1: value=" + n + ",time=" + (t2 - t1)  
    
                    / 1000.0);  
    
        }  
    
     
    
        private static int method1(int max) {  
    
            int num = 0;  
    
            for (int i = 1; i <= max; i++) {  
    
                boolean flag = true;  
    
                for (int j = 2; j < i - 1; j++) {  
    
                    if (i % j == 0) {  
    
                        flag = false;  
    
                        break;  
    
                    }  
    
                }  
    
                if (flag && i > num)  
    
                    num = i;  
    
            }  
    
            return num;  
    
        }  
    
     
    
        private static void test2(int max) {  
    
            long t1 = System.currentTimeMillis();  
    
            int threadNumber = 10;//线程数 
    
            final CountDownLatch countDownLatch = new CountDownLatch(threadNumber);  
    
            int step = max / threadNumber;  
    
            for (int i = 0; i <= max; i += step) {  
    
                if (i - step >= 0) {  
    
                    Calc calc = new Calc(i - step + 1, i, countDownLatch);  
    
                    Thread thread = new Thread(calc);  
    
                    thread.start();  
    
                }  
    
            }  
    
            try {  
    
                countDownLatch.await();  
    
            } catch (InterruptedException e) {  
    
                e.printStackTrace();  
    
            }  
    
            long t2 = System.currentTimeMillis();  
    
            System.out.println("method2: value=" + Calc.getVal() + ",time="  
    
                    + (t2 - t1) / 1000.0);  
    
        }  
    
    }  
    
     
    
    class Calc implements Runnable {  
    
     
    
        private static Integer val = 0;  
    
     
    
        private int min;  
    
        private int max;  
    
        private CountDownLatch cdl;  
    
     
    
        public Calc(int min, int max, CountDownLatch cdl) {  
    
            this.min = min;  
    
            this.max = max;  
    
            this.cdl = cdl;  
    
        }  
    
     
    
        public static int getVal() {  
    
            return val;  
    
        }  
    
     
    
        public void run() {  
    
            int num = 0;  
    
            for (int i = min; i <= max; i++) {  
    
                boolean flag = true;  
    
                for (int j = 2; j < i - 1; j++) {  
    
                    if (i % j == 0) {  
    
                        flag = false;  
    
                        break;  
    
                    }  
    
                }  
    
                if (flag && i > num)  
    
                    num = i;  
    
            }  
    
            synchronized (val) {  
    
                if (num > val)  
    
                    val = num;  
    
            }  
    
            cdl.countDown();  
    
        }  
    
     
    
    }  
    对于顺序执行统计任务完成时间非常简单,在任务对的执行前后分别通过 System.currentTimeMillis()方法得到当时的时间并且相减即可,但是对于多线程怎么操作呢
    ,我们不可能通过如下代码得到多线程执行任务的时间
      
    public static void main(String[] args) {   
    
     long t1 = System.currentTimeMillis();  
    
             Thread1.start();
    
             Thread2.start();
    
             Thread3.start();
    
             Thread4.start();
    
             Thread5.start();
    
      long t2 = System.currentTimeMillis(); 
    }
    因为得到的时间只是主线程的执行实行,对于线程Thread1,Thread2,Thread3,Thread4,Thread5的时间我们根本就没有统计,怎么解决,到java.util.concurrent包中找答案,我们有CountDownLatch这个线程同步辅助类
     
    3 CountDownLatch这个同步辅助类科普
     

    CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行,构造器中的计数值(count)实际上就是闭锁需要等待的线程数量。这个值只能被设置一次,而且CountDownLatch没有提供任何机制去重新设置这个计数值。与CountDownLatch的第一次交互是主线程等待其他线程。主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。其他N 个线程必须引用闭锁对象,因为他们需要通知CountDownLatch对象,他们已经完成了各自的任务。这种通知机制是通过 CountDownLatch.countDown()方法来完成的;每调用一次这个方法,在构造函数中初始化的count值就减1。所以当N个线程都调 用了这个方法,count的值等于0,然后主线程就能通过await()方法,恢复执行自己的任务。

    4 如何把电脑设置成单核
    超哥就在琢磨这个问题,怎么去弄个单核的电脑呢,在当今时代弄个八核的不难,找个单核的难啊,能不能把我的双核电脑关掉一个核呢,想到就百度了,哈哈,还真能,
    首先先点击Windows下左下角在搜索栏中输入MSConfig,进入Windows启动项的高级设置如下图
    我们在引导的高级选项中在处理器数的前面打上勾,并且在下拉栏中选择1 ,其他的都不需要改动,接着重启,说道重启,超哥不得不说OSGI架构的好处,如果想java的OSGI架构,只需要更改一下,而不需要重启生效,这一重启不得了,再次进入Windows下时直接卡在开始界面死机了,接连三次都是这样,超哥慌了,电脑要玩废了,不怕,第四次启动的时候超哥用了Windows的安全模式下启动,哈哈成功了 这是进入eclipse,打开测试程序 
     
    5 测试结果
     
    method1代表的时间为不采用多线程,method2代表的时间为采用多线程
     
    5.1单核的条件下测试结果
     
    我们首先设置 线程数为10
    线程数为20的情况
    线程数为30的情况
    从上面我们可以看出在单核的情况下,采用多线程是比顺序执行慢的,每次多线程都比顺序执行多了几毫秒,也印证了超哥之前的猜想,得到锁,释放锁难道不需要时间吗?
     
    5.2双核的条件下测试结果
     
    线程数为10 的情况下
    线程数为20的情况下
    线程数为30的情况下
    对比在双核的情况下,我们可以看出采用多线程运行需要的时间约为顺序执行时间的50%,在如今多核的时代下,4核,8核,多线程
    的作用可想而知了。所以学好多线程是非常有必要的
     
    在超哥带你玩转多线程系列,超哥将陆续介绍多线程的同步和调度给大家。。。。。。
  • 相关阅读:
    SQL SERVER 修改表名、列名
    AgilePLM维护中,重启能解决的问题
    联通银铃小龙卡3G流量领取方法
    更改github默认分支main为master
    SQL基础:显示不存在的分组数量为0
    关于添加EF CODE First的问题
    安装Windows Service总是发生异常!
    通过Anaconda3pip安装opencvpython包失败的处理方法(亲测有效)
    jenkins安装及配置(一)
    Windows添加多个github ssh秘钥域名映射
  • 原文地址:https://www.cnblogs.com/winAlaugh/p/5478675.html
Copyright © 2020-2023  润新知