Immutable模式

一、什么是Immutable模式?

immutable就是不变的,不发生改变的。Immutable模式中存在着确保实例状态不发生变化改变的类。这些实例不需要互斥处理。
String就是一个Immutable类,String实例所表示的字符串的内容不会变化。

二、定义一个使用Immutable模式的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    public final class Person {
private final String name;
private final String address;

public Person(String name,String address){
this.name = name;
this.address = address;
}
public String getName(){
return name;
}
public String getAddress(){
return address;
}

@Override
public String toString() {
return "[ Person : name = "+name+",address = "+address+"]";
}
}

final修饰类,无法创建子类,防止子类修改其子段值
private修饰字段,内部可见,防止子类修改字段值
final修饰了字段,赋值后不在改变

三、何时使用这种模式?

1.实例创建后,状态不再发生变化
2.实例是共享的,且被频繁访问时

四、集合类与多线程

1.ArrayList类用于提供可调整大小的数组,是非线程安全的。当多个线程并发执行读写时,是不安全的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class WriterThread extends Thread {
private final List<Integer> list;

public WriterThread(List<Integer> list){
super("WriterThread");
this.list = list;
}

@Override
public void run() {
for (int i = 0;true ; i++) {
list.add(i);
list.remove(0);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ReaderThread extends Thread{
private final List<Integer> list;

public ReaderThread(List<Integer> list){
super("ReaderThread");
this.list = list;
}

@Override
public void run() {
while (true){      
for (int n :list){          System.out.println(n);        }
System.out.println("------");
}

}
}
1
2
3
4
5
6
7
8
9
10
11
/** * 并发读写List,会出异常 
* Exception in thread "ReaderThread" java.util.NoSuchElementException
 * Exception in thread "ReaderThread"       *java.util.ConcurrentModificationException
*
*/
public class ListTest {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();new WriterThread(list).start();
new ReaderThread(list).start();
}
}

2.利用Collections.synchronizedList方法锁进行的同步

利用Collections.synchronizedList方法进行同步,就能够得到线程安全的实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class WriterThread extends Thread {
private final List<Integer> list;

public WriterThread(List<Integer> list){
super("WriterThread");
this.list = list;
}

@Override
public void run() {
for (int i = 0;true ; i++) {
list.add(i);
list.remove(0);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ReaderThread extends Thread{
private final List<Integer> list;

public ReaderThread(List<Integer> list){
super("ReaderThread");
this.list = list;
}

@Override
public void run() {
while (true){
//使用了synchronizedList,读数据时必须加锁
synchronized (list){
for (int n :list){
System.out.println(n);
}
}
System.out.println("------");
}

}
}
1
2
3
4
5
6
7
8
public class ListTest {
public static void main(String[] args) {
List<Integer> arrayList = new ArrayList<>();
List<Integer> list= Collections.synchronizedList(arrayList);
new WriterThread(list).start();
new ReaderThread(list).start();
}
}

3.使用copy-on-write 的java.util.concurrent.CopyOnWriteArrayList类

copy-on-write,就是写时复制,如果使用copy-on-write,当对集合执行 写操作时,内部已确保安全的数组就会被整体复制。复制之后,就无需在使用迭代器依次读取数据时

担心元素被修改了。所以该类不会抛出并发修改异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class WriterThread extends Thread {
private final List<Integer> list;

public WriterThread(List<Integer> list){
super("WriterThread");
this.list = list;
}

@Override
public void run() {
for (int i = 0;true ; i++) {
list.add(i);
list.remove(0);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ReaderThread extends Thread{
private final List<Integer> list;

public ReaderThread(List<Integer> list){
super("ReaderThread");
this.list = list;
}

@Override
public void run() {
while (true){
      
for (int n :list){
         System.out.println(n);
       }

System.out.println("------");
}

}
}
1
2
3
4
5
6
7
8
public class CopyOnWriteListTest {
public static void main(String[] args) {
final List<Integer> list = new CopyOnWriteArrayList<>();
new WriterThread(list).start();
new ReaderThread(list).start();
}

}

使用copy-on-write时,每次执行 写操作时都会执行复制。因此程序频繁执行写操作时,如果使用CopyOnWriteArrayList,会比较花费时间。

如果写操作比较少,读炒作频繁时,很适合用CopyOnWriteArrayList。

具体根据情况而定。