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;

扫描二维码关注公众号,回复: 913674 查看本文章

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

标准类库中用到的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);

}

猜你喜欢

转载自blog.csdn.net/qq_31350373/article/details/80292958