写入时复制(CopyOnWrite)思想
在很多应用场景中,读操作可能会远远大于写操作。由于读操作根本不会修改原有的数据,因此如果每次读取都进行加锁操作,其实是一种资源浪费。我们应该允许多个线程同时访问 List 的内部数据,毕竟读操作是线程安全的。这和 ReentrantReadWriteLock 读写锁的思想非常类似,也就是 读读共享、写写互斥、读写互斥、写读互斥。JDK中提供了 CopyOnWriteArrayList 类,相比于在读写锁的思想又更进一步。为了将读取的性能发挥到极致,CopyOnWriteArrayList 读取是完全不用加锁的,并且更厉害的是:写入也不会阻塞读取操作,只有写入和写入之间需要进行同步等待,读操作的性能得到大幅度提升。
以下示例将向您展示普通方法和用CopyOnWriteArrayList的区别
package com.charles.charles.LinkedList;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
public class TestCopyOnWriteArrayList {
public static void main(String[] args) {
HelloThread h = new HelloThread();
for (int i = 0; i < 10; i++) {
new Thread(h).start();
}
}
}
class HelloThread implements Runnable {
private static List<String> list = Collections.synchronizedList(new ArrayList<>())
static {
list.add("aaa");
list.add("bbb");
list.add("ccc");
}
@Override
public void run() {
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String next = it.next();
System.out.println(next);
list.add("AA");
}
}
}
以上代码会报错
但使用了CopyOnWriteArrayList 以后就会很正常了
在这里插入代码片package com.charles.charles.LinkedList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class TestCopyOnWriteArrayList {
public static void main(String[] args) {
HelloThread h = new HelloThread();
for (int i = 0; i < 10; i++) {
new Thread(h).start();
}
}
}
class HelloThread implements Runnable {
private static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
static {
list.add("aaa");
list.add("bbb");
list.add("ccc");
}
@Override
public void run() {
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String next = it.next();
System.out.println(next);
list.add("AA");
}
}
}
可以看到在用了CopyOnWriteArrayList后可以正常输出了