带你玩转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启动项的高级设置如下图
带你玩转java多线程系列 “道篇” 多线程的优势及利用util.concurrent包测试单核多核下多线程的效率_第1张图片
我们在引导的高级选项中在处理器数的前面打上勾,并且在下拉栏中选择1 ,其他的都不需要改动,接着重启,说道重启,超哥不得不说OSGI架构的好处,如果想java的OSGI架构,只需要更改一下,而不需要重启生效,这一重启不得了,再次进入Windows下时直接卡在开始界面死机了,接连三次都是这样,超哥慌了,电脑要玩废了,不怕,第四次启动的时候超哥用了Windows的安全模式下启动,哈哈成功了 这是进入eclipse,打开测试程序 
 
5 测试结果
 
method1代表的时间为不采用多线程,method2代表的时间为采用多线程
 
5.1单核的条件下测试结果
 
我们首先设置 线程数为10
线程数为20的情况
线程数为30的情况
从上面我们可以看出在单核的情况下, 采用多线程是比顺序执行慢的,每次多线程都比顺序执行多了几毫秒,也印证了超哥之前的猜想,得到锁,释放锁难道不需要时间吗?
 
5.2双核的条件下测试结果
 
线程数为10 的情况下
线程数为20的情况下
线程数为30的情况下
对比在双核的情况下,我们可以看出采用多线程运行需要的时间约为顺序执行时间的50%,在如今多核的时代下,4核,8核,多线程
的作用可想而知了。所以学好多线程是非常有必要的
 
在超哥带你玩转多线程系列,超哥将陆续介绍多线程的同步和调度给大家。。。。。。

你可能感兴趣的:(带你玩转java多线程系列 “道篇” 多线程的优势及利用util.concurrent包测试单核多核下多线程的效率)