Java并发编程实战~Immutability模式
????????解決并發(fā)問題,其實最簡單的辦法就是讓共享變量只有讀操作,而沒有寫操作。這個辦法如此重要,以至于被上升到了一種解決并發(fā)問題的設計模式:不變性(Immutability)模式。所謂不變性,簡單來講,就是對象一旦被創(chuàng)建之后,狀態(tài)就不再發(fā)生變化。換句話說,就是變量一旦被賦值,就不允許修改了(沒有寫操作);沒有修改操作,也就是保持了不變性。
快速實現(xiàn)具備不可變性的類
????????將一個類所有的屬性都設置成 final 的,并且只允許存在只讀方法,那么這個類基本上就具備不可變性了。更嚴格的做法是這個類本身也是 final 的,也就是不允許繼承。因為子類可以覆蓋父類的方法,有可能改變不可變性,所以推薦你在實際工作中,使用這種更嚴格的做法。
????????經(jīng)常用到的 String 和 Long、Integer、Double 等基礎(chǔ)類型的包裝類都具備不可變性。
利用享元模式避免創(chuàng)建重復對象
????????享元模式本質(zhì)上其實就是一個對象池,利用享元模式創(chuàng)建對象的邏輯也很簡單:創(chuàng)建之前,首先去對象池里看看是不是存在;如果已經(jīng)存在,就利用對象池里的對象;如果不存在,就會新創(chuàng)建一個對象,并且把這個新創(chuàng)建出來的對象放進對象池里。
使用 Immutability 模式的注意事項
1. 對象的所有屬性都是 final 的,并不能保證不可變性;
2. 不可變對象也需要正確發(fā)布。
例如下面的代碼中,Bar 的屬性 foo雖然是 final 的,依然可以通過 setAge() 方法來設置 foo 的屬性 age。所以,在使用Immutability 模式的時候一定要確認保持不變性的邊界在哪里,是否要求屬性對象也具備不可變性。
class Foo{int age = 0;int name = "abc"; }final class Bar {final Foo foo;void setAge(int a){foo.age = a;} }下面我們再看看如何正確地發(fā)布不可變對象。不可變對象雖然是線程安全的,但是并不意味著引用這些不可變對象的對象就是線程安全的。例如在下面的代碼中,Foo 具備不可變性,線程安全,但是類 Bar 并不是線程安全的,類 Bar 中持有對 Foo 的引用 foo,對 foo這個引用的修改在多線程中并不能保證可見性和原子性。
//Foo 線程安全 final class Foo{final int age = 0;final int name = "abc"; }//Bar 線程不安全 class Bar {Foo foo;void setFoo(Foo f){this.foo = f;} }如果你的程序僅僅需要 foo 保持可見性,無需保證原子性,那么可以將 foo 聲明為volatile 變量,這樣就能保證可見性。如果你的程序需要保證原子性,那么可以通過原子類來實現(xiàn)。
public class SafeWM {class WMRange{final int upper;final int lower;WMRange(int upper,int lower){// 省略構(gòu)造函數(shù)實現(xiàn)}}final AtomicReference<WMRange>rf = new AtomicReference<>(new WMRange(0,0));// 設置庫存上限public void setUpper(int v){while(true){WMRange or = rf.get();// 檢查參數(shù)合法性if(v < or.lower){throw new IllegalArgumentException();}WMRange nr = new WMRange(v, or.lower);if(rf.compareAndSet(or, nr)){return;}}} } 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的Java并发编程实战~Immutability模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Effective Java~43. 方
- 下一篇: Java并发编程实战~ThreadLoc