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(); } }
,我们不可能通过如下代码得到多线程执行任务的时间
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核,多线程
的作用可想而知了。所以学好多线程是非常有必要的
在超哥带你玩转多线程系列,超哥将陆续介绍多线程的同步和调度给大家。。。。。。