實現方式 : 將他們的狀態封裝起來,並對每一個公有方法都進行同步, 使得每次只有一個線程能夠訪問. java
複合操做 並不是線程安全. 好比 迭代, 條件運算等.數組
在對同步容器類的複合操做加鎖時必定要以容器對象爲鎖對象, 保證複合操做的鎖對象和容器使用的鎖對象一致.才能實現一個線程安全的複合操做安全
public static void getLast(Vector<?> list) { // 此處的鎖對象必須和 Vector 內部的鎖對象一致 synchronized (list) { int lastIndex = list.size()-1; list.remove(lastIndex); } }
在容器的迭代過程中被修改(結構上被改變)時會拋出 ConcurrentModificationException併發
解決方法 : 在迭代過程當中持有容器的鎖. 並在全部對共享容器進行迭代的地方加鎖框架
如下操做也會間接的進行容器的迭代操做異步
toString() , hashCode() , equals() 等不少方法都出觸發容器的迭代操做. ide
BlockingQueue(阻塞隊列接口)工具
LinkedBlockingQueue 相似與 LinkedListspa
ArrayBlockingQueue 相似與 ArrayList線程
PriorityBlockingQueue 按優先級排序的隊列
SynchronousQueue 每一個插入操做必須等待另外一個線程的對應移除操做 ,反之亦然。很是適合作交換工做,生產者的線程和消費者的線程同步以傳遞某些信息、事件或者任務。
生產者和消費者設計也可使用 Executor 任務執行框架來實現, 其自己也使用 生產者--消費者模式
雙端隊列
工做密取
處理 InterruptedException
做用 : 用來確保某些活動直到其餘活動都完成後才執行.
用法一 : 建立必定數量的線程,多個線程併發的執行任務
package com.pinnet.test; import java.util.concurrent.CountDownLatch; public class CountLatchTest { public void timeTask(int threadNumbers, Runnable task) throws InterruptedException { CountDownLatch start = new CountDownLatch(1); CountDownLatch end = new CountDownLatch(threadNumbers); for (int i = 0; i < threadNumbers; i++) { new Thread() { public void run() { try { // 全部線程在起始門等待 start.await(); // 執行任務 task.run(); // 結束門遞減 end.countDown(); } catch (InterruptedException e) { } } }.start(); } // 全部工做線程開始執行 start.countDown(); // 全部工做線程啓動後主線程當即登待 end.await(); System.out.println("開始主線程"); } }
用法二: 建立必定數量的線程,多個線程依次的執行任務
public void timeTask2(int threadNumbers, Runnable task) throws InterruptedException { CountDownLatch start = new CountDownLatch(threadNumbers); // 任務一次執行 for (int i = 0; i < threadNumbers; i++) { new Thread() { public void run() { // 任務開始 task.run(); // 遞減 start.countDown(); } }.start(); } // 主線程阻塞直到計數器爲0 start.await(); System.out.println("開始主線程"); }
一種可生成結果,可異步取消的計算.
public class FutureTaskTest { // 建立任務 private final FutureTask<Integer> future = new FutureTask<>(new Callable<Integer>() { public Integer call() { return 123; } }); // 建立線程 private final Thread thread = new Thread(future); // 對外提供方法啓動線程 public void start() { thread.start(); } // 獲取計算結果 public Integer get() { try { return future.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); return null; } } }
閉鎖和柵欄的區別 :
基本使用 :
用法一 : CyclicBarrier(int number)
await() 調用 number 次後全部調用 await() 的線程繼續執行 , 不然線程在await() 阻塞
public void barrier() { int number = 6; // 參數表示屏障攔截的線程數量 // barrier.await() 調用 number 次後全部線程的阻塞狀態解除 CyclicBarrier barrier = new CyclicBarrier(number); for (int i = 0; i < number; i++) { new Thread(new Runnable() { @Override public void run() { System.out.println("此線程任務已經完成"); try { // 調用await方法告訴CyclicBarrier我已經到達了屏障,而後當前線程被阻塞。 barrier.await(); System.out.println("全部線程執行完成"); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } } }).start(); } }
用法二 : CyclicBarrier(int parties, Runnable runnable) 指定數量的線程到達屏障點後 執行 runnable
public void barrier2() { int number = 6; // 參數表示屏障攔截的線程數量 // barrier.await() 調用 number 次後全部線程的阻塞狀態解除 CyclicBarrier barrier = new CyclicBarrier(number, new Runnable() { @Override public void run() { // 指定數量的線程到達屏障點後執行 barrier() barrier(); } }); for (int i = 0; i < number; i++) { new Thread(new Runnable() { @Override public void run() { System.out.println("此線程任務已經完成"); try { // 調用await方法告訴CyclicBarrier我已經到達了屏障,而後當前線程被阻塞。 barrier.await(); System.out.println("全部線程執行完成"); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } } }).start(); } }
雙方形式的柵欄 Exchanger