测试解决的问题:
线程的上下文切换真的很耗时么,耗时的话到底耗时到什么程度。
测试的机器是4核cpu,处理同样多的任务,看看耗时情况。
代码如下:
private static void testContextSwitch() { AtomicInteger count = new AtomicInteger(0); long totolLoopNum = 1000000000; int threadNum = 1000; long loopNum = totolLoopNum/threadNum; System.out.println("totolLoopNum:"+totolLoopNum); System.out.println("threadNum:"+threadNum+"\tloopNum:"+loopNum); ExecutorService e = Executors.newFixedThreadPool(threadNum); long startTime = System.currentTimeMillis(); for (int i = 0; i < threadNum; i++) { e.execute(createLoopRunnable(count, loopNum, threadNum, startTime)); } } private static Runnable createLoopRunnable(final AtomicInteger count, final long loopNum, final int threadNum, final long startTime) { return new Runnable() { @Override public void run() { for (int j = 0; j < 100; j++) { int i = 0; while (true) { if (i > loopNum) break; i++; } } int total = count.incrementAndGet(); if (total == threadNum) System.out.println("cost:" + (System.currentTimeMillis() - startTime)); } }; }
输出结果如下:
// totolLoopNum:1000000000 // threadNum:1 loopNum:1000000000 // cost:127198 cpu使用20%-40% // totolLoopNum:1000000000 // threadNum:2 loopNum:500000000 // cost:67120 cpu使用50% // totolLoopNum:1000000000 // threadNum:4 loopNum:250000000 // cost:36015 cpu使用100% // totolLoopNum:1000000000 // threadNum:64 loopNum:15625000 // cost:35905 cpu使用100% // totolLoopNum:1000000000 // threadNum:512 loopNum:1953125 // cost:35905 // totolLoopNum:1000000000 // threadNum:1000 loopNum:1000000 // cost:35955
可以看出:
1.在线程小于4的情况下cpu是不能跑到100%的。
2.随着线程数目的增加,处理任务的耗时越来越短,知道开到1000个线程的时候才开始有微弱的增加。
可以看出线程的上下文切换貌似不是很耗时。。。
实际应用中,比如阻塞读数据。经常会写如下类似代码:
//socket连接没有中断,阻塞读数据 while(socket != null) { //阻塞的读写数据 }
代码1:
while (true) { // 阻塞的读写数据 try { if (queue.size() != 0) { System.out.println(1); // read; } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
代码2:
while (true) { // 阻塞的读写数据 try { if (queue.take() != null) { System.out.println(1); // read; } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
加入几个阻塞线程到线程池中发现,代码2加入后消耗的实践较少,代码1加入后消耗的实践较多。
通过jstack分析发现:
代码2中的线程处于WAITING状态,而代码1所有线程都是RUNNABLE。
java.util.concurrent.locks.LockSupport
http://forums.sun.com/thread.jspa?threadID=5353864
"pool-1-thread-3" prio=6 tid=0x01a0f800 nid=0x1fc4 waiting on condition [0x0c07f000..0x0c07fbe8] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x03ae66f0> (a java.util.concurrent.SynchronousQueue$TransferStack) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158) at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:422) at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:323) at java.util.concurrent.SynchronousQueue.take(SynchronousQueue.java:857) at lsd.Main$2.run(Main.java:205) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619)