java多線程之Immutable模式

Immutable

Immutable(不可變的),Immutable角色是一個類,在這個角色中,字段的值不可修改,也不存在修改字段內容的方法。Immutable角色的實例被創建後,狀態將不再發生變化。無需將Immutable角色的方法聲明爲synchronized

Immutable模式的類圖:

 

何時使用Immutable:

1. 實例創建後,狀態不再發生變化時

字段聲明爲final,不存在setter方法

2. 實例是共享的,且被頻繁訪問時

不需要使用synchronized,這樣就能提高性能。

java標準庫類中有成對的mutableimmutable

java.lang.StringBuffer (mutable)java.lang.String(immutable)

所以如果需要頻繁修改字符串內容,則使用StringBuffer(改寫時需要妥善使用synchronized;

如果不需要修改字符串內容,只是引用其內容。

標準類庫中用到的Immutable模式:

表示字符串的java.lang.String

表示大數字的java.math.BigInteger類,java.math.BigInteger

表示正則表達式的java.util.regex.Pattern類等

非線程安全的java.util.ArrayList的類

一下是實例代碼

public class WriterThread extends Thread{

private final List<Integer> list;

 

public WriterThread(List<Integer> list) {

super();

this.list = list;

}

public void run(){

for (int i = 0;true; i++) {

list.add(i);

list.remove(0);

}

}

}

public class ReaderThread extends Thread{

private final List<Integer> list;

 

public ReaderThread(List<Integer> list) {

super();

this.list = list;

}

public void run(){

while (true) {

for (int n:list) {

System.out.println(n);

}

}

}

}

public class Main {

public static void main(String[] args) {

List<Integer> list = new ArrayList<Integer>();

new WriterThread(list).start();

new ReaderThread(list).start();

}

}

ArrayList在被多個線程同時進行讀寫操作時而失去安全性時,便會拋出

Exception in thread "Thread-1" java.util.ConcurrentModificationException

at java.util.ArrayList$Itr.checkForComodification(Unknown Source)

at java.util.ArrayList$Itr.next(Unknown Source)

at day2.ReaderThread.run(ReaderThread.java:15)

 

利用Collections.synchronizedList方法進行的同步

java.util.ArrayList是非線程安全的類,但如果使用Collections.sysnchronizedList方法進行同步,就能得到線程安全的實例。

public class ReaderThread extends Thread{

private final List<Integer> list;

 

public ReaderThread(List<Integer> list) {

super();

this.list = list;

}

public void run(){

while(true){

synchronized (list) {

for(int n:list){

System.out.println(n);

}

}

}

}

}

public class Main {

public static void main(String[] args) {

 //final只是說你的當前這個list不能指向內存其他地方了

 final List<Integer> list= Collections.synchronizedList(new ArrayList<Integer>());

 new WriterThread(list).start();

 new ReaderThread(list).start();

}

}

WriterThread與前面例子代碼用例一致,因爲寫線程不斷改寫值,所以讀取的值是跳躍的

 

CopyOnWriteArrayList

採用copy-on-write技術避免讀寫衝突,所謂copy-on-write,就是寫時複製的意思,當集合執行寫操作的時候,內部已確保安全的數組就會被整體複製。

實例代碼:讀寫線程類與ArrayList的實例相同

public class Main {

public static void main(String[] args) {

final List<Integer> list = new CopyOnWriteArrayList<Integer>();

new ReaderThread(list).start();

new WriterThread(list).start();

}

}

 

Immutable模式:

當一個類的實例創建完成後,其狀態就完全不會發生變化。這時,該類的方法就算被多個線程同時執行也沒關係,所以這些方法就無需聲明爲synchronized,這樣就可以在生存型和安全性不缺失的同時提高性能。

 

下面的sreplace替換成了CAT,有人覺得這樣違背了immutable的模式,實際上着個字符串s沒有變,只是replace這個方法新建了一個實例而已。

public static void main(String[] args) {

String s = “BAT”;

System.out.print(s.replace(‘B’,’C’));

}

 

如下代碼,getInfo方法獲取的info字段中保存的實例並不是String實例,而是StringBuffer實例,StringBuffer類與String類不同,包含修改內部狀態的方法,所以info子彈的內容也可以被外部修改,String類的replace方法並不會修改實例本身,但StringBufferreplace會修改實例本身,由於info字段聲明瞭final,所以info字段的值本身並不會改變,但是info字段所指向的實例的狀態卻可能發生改變。

public final class UserInfo {

private final StringBuffer info;

public UserInfo(String name,String address){

this.info = new StringBuffer("<info name=\""+name+"\"address=\""+address+"\"+/>");

}

public StringBuffer getInfo(){

return info;

}

public String toString(){

return "[userInfo:"+info+"]";

}

}

public static void main(String[] args) {

UserInfo userinfo = new UserInfo("Alice", "America");

System.out.println("userinfo="+userinfo);

//修改狀態

StringBuffer info = userinfo.getInfo();

System.out.println(info);

info.replace(12, 17, "Boddy");

System.out.println("userinfo="+userinfo);

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章