併發應用中不可變資料結構
併發並行程式設計是當前熱點,過去我們知道使用鎖synchronization來解決多執行緒併發訪問同一個資料結構時共享問題,甚至我們懷疑資料共享方式本身是不是就錯了?所以,雲端計算的資料喂任務模式開始盛行,但是資料共享方式從我們開始軟體第一天就已經習慣,如何在這個共享模式下實現高併發訪問呢?也就是不使用鎖synchronization,那麼就透過不變性Immutable模式來實現。
如果我們有一個Contact物件的集合:聯絡人名單集合,然後給這個名單中每個聯絡人傳送Email:
public void sendMessages(Map contactMap) {
sendEmail(contactMap.values());
}
contactMap是Contact集合,contactMap.values是遍歷contactMap中元素Contact物件。如果在遍歷發生Email同時,有新的Contact物件加入到contactMap集合中,這時會丟擲併發錯誤。當然,可以使用ConcurrentMap來實現Map。
但是該文提出一個不可變Map也許能獲得更好地併發效能。
該Map的特點就是遵循值物件模型的特點,集合Map作為一個值物件模型,一旦其元素髮生變化,如新增或刪除元素,返回一個新的集合Map物件。
獲得使用該不可變Map的程式碼如下:
這樣,透過避免使用鎖synchronization,而是透過業務設計出值物件,然後使用不可變模式來獲得更好地效能,從這裡也可以看出物件導向設計並不會影響效能,反而能提升效能。
Immutable Data Structures in Concurrent Java Applications提出了實現集合物件邊讀邊修改的併發實現方式。
首先指出volatile 的不足,因為不能保證操作volatile 欄位方法的原子性,這樣,還是需要鎖synchronization來修飾其操作方法,該文提出使用final來替代volatile,如果需要修改final的欄位值,就用這個物件來替換,這個概念符合DDD中值物件定義,值物件是不可變的,一旦變化,整個物件更換,同時也符合併發模型,如下類:
public final class Contact { private final String name; private final String email; private final phone; public Contact(String name, String email, String phone) { this.name = name; this.email = email; this.phone = phone; } public String getName() {return name;} public String getEmail() {return email;} public String getPhone() {return phone;} } <p class="indent"> |
如果我們有一個Contact物件的集合:聯絡人名單集合,然後給這個名單中每個聯絡人傳送Email:
public void sendMessages(Map contactMap) {
sendEmail(contactMap.values());
}
contactMap是Contact集合,contactMap.values是遍歷contactMap中元素Contact物件。如果在遍歷發生Email同時,有新的Contact物件加入到contactMap集合中,這時會丟擲併發錯誤。當然,可以使用ConcurrentMap來實現Map。
但是該文提出一個不可變Map也許能獲得更好地併發效能。
public class ImmutableMap implements Map { private final Map map; public ImmutableMap() { this(Collections.EMPTY_MAP); } public ImmutableMap immutablePut(K key, V value) { Map newMap = new HashMap(map); newMap.put(key, value); return new ImmutableMap(newMap);//創新新的不可變Map } public ImmutableMap immutableRemove(K key) { Map newMap = new HashMap(map); newMap.remove(key); return new ImmutableMap(newMap); } private ImmutableMap(Map delegate) { this.map = Collections.unmodifiableMap(delegate); } // All the map methods are simply delegated to the map field. // To conserve space they are not shown here. } <p class="indent"> |
該Map的特點就是遵循值物件模型的特點,集合Map作為一個值物件模型,一旦其元素髮生變化,如新增或刪除元素,返回一個新的集合Map物件。
獲得使用該不可變Map的程式碼如下:
public class ContactService { private final ReentrantLock lock = new ReentrantLock(); //注意 volatile private volatile ImmutableMap contacts = new ImmutableMap(); public void addContact(Contact contact) { lock.lock();//使用鎖來實現變動 try { contacts = contacts.immutablePut(contact.getName(), contact); } finally { lock.unlock(); } } public ImmutableMap getContacts() { return contacts; } } <p class="indent"> |
這樣,透過避免使用鎖synchronization,而是透過業務設計出值物件,然後使用不可變模式來獲得更好地效能,從這裡也可以看出物件導向設計並不會影響效能,反而能提升效能。
相關文章
- .NET併發程式設計-資料結構不可變性程式設計資料結構
- Java中的不可變資料結構Java資料結構
- Java中的不可變資料結構 - Jworks.ioJava資料結構
- var+不可變資料結構 vs val+可變資料結構資料結構
- java併發資料結構之CopyOnWriteArrayListJava資料結構
- java八股 併發+資料結構Java資料結構
- Java中結構化併發Java
- 應用中如何使用適當的資料結構資料結構
- 【資料結構】——堆及其應用資料結構
- 雜湊資料結構以及在HashMap中的應用資料結構HashMap
- java 中構建不可變物件Java物件
- 【資料結構】歸併排序!!!資料結構排序
- 【資料結構】歸併排序資料結構排序
- Java併發設計模式--不可變模式(immutable)Java設計模式
- 可變資料型別(mutable)與不可變資料型別(immutable)總結資料型別
- 資料結構筆記-棧的應用資料結構筆記
- 資料結構實驗:連結串列的應用資料結構
- 不可變資料之Immutable
- 堆疊的應用——用JavaScript描述資料結構JavaScript資料結構
- 【資料結構】棧的應用——中綴表示式求值(c++)資料結構C++
- 資料結構 歸併排序 C++資料結構排序C++
- 資料結構--線段樹合併資料結構
- 前端資料結構(3)之連結串列及其應用前端資料結構
- mysql資料庫多表同結構合併資料MySql資料庫
- 單連結串列的歸併(資料結構)資料結構
- 前端資料結構(1)之棧及其應用前端資料結構
- Redis的資料結構與應用場景Redis資料結構
- Redis的資料結構及應用場景Redis資料結構
- 打通 Java 任督二脈 —— 併發資料結構的基石Java資料結構
- 資料庫資料變成樹型結構資料庫
- 高併發,大資料量系統的資料結構優化思路大資料資料結構優化
- 資料結構:歸併排序(非遞迴)資料結構排序遞迴
- 前端資料結構(2)之佇列及其應用前端資料結構佇列
- JavaScript資料結構——集合的實現與應用JavaScript資料結構
- 《資料結構》實驗08--樹及其應用資料結構
- 資料結構 — 並查集的原理與應用資料結構並查集
- c++11併發程式設計歷程(15):併發設計以及併發設計資料結構的思考C++程式設計資料結構
- 攜程大資料實踐:高併發應用架構及推薦系統案例大資料應用架構