JAVA多线程(一)
进程与线程:
一个进程可以包含多个线程。多个线程可以并行,但是一个时间点只能有一个线程是运行状态。
线程的状态:
查看API可以,线程的状态分为五种:
(JVM里面的状态:These states are virtual machine states which do not reflect any operating system thread states)
1. NEW: 当新建一个Thread的时候,当前线程的处于新建状态,线程还未开始。
2. RUNNABLE: 调用Thread的start方法,线程进入可运行状态,在这个状态下,线程开始处理工作,还有一种情况是未真正处理,还正在等待操作系统的调用。
3. BLOCKED: 线程的阻塞状态。一种情况下当调用wait方法时,当前线程释放锁,其他线程获取锁,开始处理,当前线程进入阻塞状态。
4. WAITING: 不定期等待状态。等待其他线程的notify.
5. TIMED_WAITING:有一定期限的等待状态,与WAITING最明显的区别是Thread.sleep(). 可以指定sleep时间。
6. TERMINATED: 终止状态。线程处理完成。
两个JDK自带的同步工具类:CountDownLatch 和CyclicBarrier
先上代码:
package com.my.thread; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CountDownLatchTest { static CountDownLatch latch = new CountDownLatch(1); static CountDownLatch downLatch = new CountDownLatch(10); static ExecutorService service = Executors.newCachedThreadPool(); public static void main(String[] args) { final long start = System.currentTimeMillis(); for (int i = 0; i < 10; i++) { final int index = i+1; Runnable runnable = new Runnable() { @Override public void run() { try { latch.await(); long end = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+"===已鸣枪,第"+index+"位运动员出发,反应时间:"+(end-start)+"ms"); Thread.sleep((long) (Math.random() * 10000)); end = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+"===第"+index+"位运动员完成,用时"+(end-start)+"ms"); downLatch.countDown(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; service.execute(runnable); } try { System.out.println("鸣枪开始!"); latch.countDown(); downLatch.await(); System.out.println("比赛结束"); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } service.shutdown(); } }
CountDownLatchTest .java
构造器中的计数值(count)实际上就是闭锁需要等待的线程数量。这个值只能被设置一次,而且CountDownLatch没有提供任何机制去重新设置这个计数值。
与CountDownLatch的第一次交互是主线程等待其他线程。主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。
这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。
1 package com.my.thread; 2 3 import java.util.concurrent.BrokenBarrierException; 4 import java.util.concurrent.CyclicBarrier; 5 import java.util.concurrent.ExecutorService; 6 import java.util.concurrent.Executors; 7 8 public class ThreadCycleBarrire { 9 public static void main(String[] args) { 10 ExecutorService service = Executors.newCachedThreadPool(); 11 final CyclicBarrier cb = new CyclicBarrier(3); // 三个线程同时到达 12 for (int i = 0; i < 3; i++) { 13 Runnable runnable = new Runnable() { 14 public void run() { 15 try { 16 // Thread.sleep((long) (Math.random() * 10000)); 17 System.out.println( 18 "线程" + Thread.currentThread().getName() + "即将到达集合地点1,当前已有" + (cb.getNumberWaiting() + 1) 19 + "个已到达" + (cb.getNumberWaiting() == 2 ? "都到齐了,继续走啊" : "正在等候")); 20 try { 21 cb.await(); 22 } catch (BrokenBarrierException e) { 23 // TODO Auto-generated catch block 24 e.printStackTrace(); 25 } 26 Thread.sleep((long) (Math.random() * 10000)); 27 System.out.println( 28 "线程" + Thread.currentThread().getName() + "即将到达集合地点2,当前已有" + (cb.getNumberWaiting() + 1) 29 + "个已到达" + (cb.getNumberWaiting() == 2 ? "都到齐了,继续走啊" : "正在等候")); 30 try { 31 cb.await(); 32 } catch (BrokenBarrierException e) { 33 // TODO Auto-generated catch block 34 e.printStackTrace(); 35 } 36 Thread.sleep((long) (Math.random() * 10000)); 37 System.out.println( 38 "线程" + Thread.currentThread().getName() + "即将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1) 39 + "个已到达" + (cb.getNumberWaiting() == 2 ? "都到齐了,继续走啊" : "正在等候")); 40 try { 41 cb.await(); 42 } catch (BrokenBarrierException e) { 43 // TODO Auto-generated catch block 44 e.printStackTrace(); 45 } 46 } catch (InterruptedException e) { 47 // TODO Auto-generated catch block 48 e.printStackTrace(); 49 } 50 } 51 }; 52 service.execute(runnable); 53 } 54 service.shutdown(); 55 } 56 }
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。
CyclicBarrier 可用于综合统计,用CyclicBarrier(int num,Runable run),最后运行run里面的方法。