Semaphore實現信號量。 java
Semaphore能夠維護當前訪問自身的線程個數,並提供了同步機制。使用Semaphore能夠控制同時訪問資源的線程個數。例如:實現一個文件容許的併發訪問數。 併發
單個信號量的Semaphore對象能夠實現互斥鎖的功能,而且能夠是由一個線程得到了鎖,再由另外一個線程釋放鎖。這可應用於死鎖恢復的一些場合。 dom
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class SemaphoreTest { public static void main(String[] args) { ExecutorService es = Executors.newCachedThreadPool(); final Semaphore sp = new Semaphore(3); for (int i = 0; i < 10; i++) { Runnable r = new Runnable() { @Override public void run() { try { sp.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("線程"+Thread.currentThread().getName()+"進入,當前已有併發"+(3-sp.availablePermits())); try { Thread.sleep(new Random().nextInt(10000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("線程"+Thread.currentThread().getName()+"即將離開"); sp.release(); System.out.println("線程"+Thread.currentThread().getName()+"已離開,當前已有併發"+(3-sp.availablePermits())); } }; es.execute(r); } es.shutdown(); } }
障礙器。表示你們彼此等待,你們集合好後纔開始出發,分散活動後又在指定地點集合碰面。 ide
import java.util.Date; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CyclicBarrierTest { public static void main(String[] args) { ExecutorService es = Executors.newCachedThreadPool(); final CyclicBarrier cb = new CyclicBarrier(5); for (int i = 0; i < 5; i++) { Runnable r = new Runnable() { @Override public void run() { try { Thread.sleep(new Random().nextInt(10000)); System.out.println(new Date()+":線程"+Thread.currentThread().getName()+"到達目的地1,當前已到達"+(cb.getNumberWaiting()+1)+",正在等候"); cb.await(); System.out.println(new Date()+":全部線程已到達,向目的地2出發"); Thread.sleep(new Random().nextInt(10000)); System.out.println(new Date()+":線程"+Thread.currentThread().getName()+"到達目的地2,當前已到達"+(cb.getNumberWaiting()+1)+",正在等候"); cb.await(); System.out.println(new Date()+":全部線程已到達,向目的地3出發"); Thread.sleep(new Random().nextInt(10000)); System.out.println(new Date()+":線程"+Thread.currentThread().getName()+"到達目的地3,當前已到達"+(cb.getNumberWaiting()+1)+",正在等候"); cb.await(); System.out.println(new Date()+":全部線程已到達,任務結束"); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }; es.execute(r); } es.shutdown(); } }
猶如倒計時計數器,調用CountDownLatch對象的countDown()方法就將計數器-1,當計數器到達0時,則全部等待者或者單個等待着開始執行。 ui
import java.util.Date; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CountDownLatchTest { public static void main(String[] args) { ExecutorService es = Executors.newCachedThreadPool(); final CountDownLatch cdOrder = new CountDownLatch(1); final CountDownLatch cdAnswer = new CountDownLatch(5); for (int i = 0; i < 5; i++) { Runnable r = new Runnable() { @Override public void run() { try { //Thread.sleep(new Random().nextInt(10000)); System.out.println(new Date()+":線程"+Thread.currentThread().getName()+"準備接受命令"); cdOrder.await(); System.out.println(new Date()+":線程"+Thread.currentThread().getName()+"已接受命令"); Thread.sleep(new Random().nextInt(10000)); System.out.println(new Date()+":線程"+Thread.currentThread().getName()+"處理命令"); cdAnswer.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } }; es.execute(r); } try { Thread.sleep(new Random().nextInt(10000)); System.out.println(new Date()+":線程"+Thread.currentThread().getName()+"即將發佈命令"); cdOrder.countDown(); System.out.println(new Date()+":線程"+Thread.currentThread().getName()+"已發佈命令,正等待結果"); cdAnswer.await(); System.out.println(new Date()+":線程"+Thread.currentThread().getName()+"已收到全部響應結果"); } catch (Exception e) { e.printStackTrace(); } es.shutdown(); } }
Exchanger用於兩個線程之間的數據交換。每一個線程在完成必定任務後想與對方交換數據,第一個先拿出數據的線程將一直等待第二個線程拿着數據的到來,才能彼此交換數據。 spa
import java.util.Date; import java.util.Random; import java.util.concurrent.Exchanger; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Exchanger交換機 兩個線程之間用戶交換數據 */ public class ExchangerTest { public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); // 線程之間交換數據 final Exchanger exchanger = new Exchanger(); service.execute(new Runnable() { public void run() { try { String data = "【數據1】"; System.out.println(new Date()+":"+Thread.currentThread().getName() + "準備把" + data + "換出去"); Thread.sleep(new Random().nextInt(10000)); String data2 = (String) exchanger.exchange(data); System.out.println(new Date()+":"+Thread.currentThread().getName() + "換回的數據是" + data2); } catch (InterruptedException e) { e.printStackTrace(); } } }); service.execute(new Runnable() { public void run() { try { String data = "【數據2】"; System.out.println(new Date()+":"+Thread.currentThread().getName() + "準備把" + data + "換出去"); Thread.sleep(new Random().nextInt(10000)); String data2 = (String) exchanger.exchange(data); System.out.println(new Date()+":"+Thread.currentThread().getName() + "換回的數據是" + data2); } catch (Exception e) { e.printStackTrace(); } } }); } }