1、CopyOnWriteArrayList
ArrayList的一个线程安全的实体。其中所有可变操作都是通过对底层数组经常一次新的复制来实现的。
比如add(E)时,容器自动copy一次出来然后在尾部添加。看源码:
public boolean add(E e) {
final ReentrantLock lock = this.lock; // 获取独占锁
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);// 重新生成一个新的数组实例,并将原始数组的元素拷贝到新数组中
newElements[len] = e; // 添加新的元素到新数组的末尾
setArray(newElements); // 更新底层数组
return true;
} finally {
lock.unlock();
}
}
可以看出,先加锁,复制一份数组,然后在尾部添加。
下面举出remove源码:
public E remove(int index) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
E oldValue = get(elements, index); // 获取volatile数组中指定索引处的元素值
int numMoved = len - index - 1;
if (numMoved == 0) // 如果被删除的是最后一个元素,则直接通过Arrays.copyOf()进行处理,而不需要新建数组
setArray(Arrays.copyOf(elements, len - 1));
else {
Object[] newElements = new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index); // 拷贝删除元素前半部分数据到新数组中
System.arraycopy(elements, index + 1, newElements, index, numMoved);// 拷贝删除元素后半部分数据到新数组中
setArray(newElements); // 更新volatile数组
}
return oldValue;
} finally {
lock.unlock();
}
}
(1)在副本上面执行加锁操作,获取独占锁,防止其他线程同时修改数据,不会出现ConcurrentModificationException异常。 ArrayList中在多线程下执行修改会报这个异常。
(2) 底层数组Object[] array用变量volatile修饰,当数组更新时,其他线程能得到最新的值。
(3) CopyOnWriteArrayList适合在读多写少的并发应用中。比如缓存。因为写操作时,执行加锁,然后对整个list的copy操作相当耗时。
(4)迭代器支持hasNext(), next()等不可变操作,但不支持可变 remove()等 操作。
(5)使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照。
2、CopyOnWriteArraySet
(1)继承AbstractSet类,实现Set接口,元素不可以重复,它的底层结构时采用动态的数组。
(2)包含CopyOnWriteArrayList对象(final)。线程安全机制也是通过volatile和互斥锁实现的。
(3)添加操作时,是根据addIfAbsent()和addAllAbsent()这两个添加元素的API来判断元素是否存在,再决定是否添加。
(4)当判断元素不在其中时(这个操作未加锁,真正执行添加操作时原数组可能已改变或者添加的数已经在其中),则还需进行一次最新的数组复制,继续进行判断。
请看添加元素源码:
public boolean add(E e) {
return al.addIfAbsent(e); //al是CopyOnWriteArraySet里面定义的CopyOnWriteArrayList
}
public boolean addIfAbsent(E e) {
Object[] snapshot = getArray();//数组快照
return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
addIfAbsent(e, snapshot);
}
private static int indexOf(Object o, Object[] elements,
int index, int fence) { //判断对象在数组中的位置
if (o == null) {
for (int i = index; i < fence; i++)
if (elements[i] == null)
return i;
} else {
for (int i = index; i < fence; i++)
if (o.equals(elements[i]))
return i;
}
return -1;
}
private boolean addIfAbsent(E e, Object[] snapshot) { //添加元素不存在,执行添加操作
final ReentrantLock lock = this.lock; //获取抢占锁
lock.lock();
try {
Object[] current = getArray(); //取得当前最新的数组
int len = current.length;
if (snapshot != current) { //如果当前最新的数组和之前得到的数组快照不一样
// Optimize for lost race to another addXXX operation
int common = Math.min(snapshot.length, len);
//与之前得到的数组状态之前比较,可能有其他线程修改0-common-1中的元素
for (int i = 0; i < common; i++) if (current[i] != snapshot[i] && eq(e, current[i])) return false; //两个数组处于相同位置的元素比较和添加元素e已经在当前数组中,则不添加 if (indexOf(e, current, common, len) >= 0)//添加元素e在common~len-1中,不添加 return false; } Object[] newElements = Arrays.copyOf(current, len + 1);// 数组拷贝 newElements[len] = e; //添加尾部 setArray(newElements); //更新底层数组 return true; } finally { lock.unlock(); } }
3、ConcurrentHashMap
锁分离技术,多个segment段来处理并发操作,在此不多叙述,请看我的另一篇博客,会有详解:
链接:”ConcurrentHashMap源码解析
Java通过Executors提供四种线程池,分别为:
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
executorService.shutdown();
import java.util.concurrent.*;
public class CallableTest {
public static void main(String[] args) throws InterruptedException, ExecutionException{
ExecutorService es = Executors.newCachedThreadPool(); //创建线程池
Future fs = es.submit(new TaskWithResult(1)); //提交callable任务
//Thread.sleep(1000); 1.线程未完成,打印"Future result is not yet complete"
Thread.sleep(1000);//2.线程已完成,取得对应的String值
if(fs.isDone()){
System.out.println(fs.get());
}else {
System.out.println("Future result is not yet complete");
}
}
}
class TaskWithResult implements Callable {
private int id;
public TaskWithResult(int id) {
this.id = id;
}
@Override
public String call() throws Exception {
return "返回结果为:"+id;
}
}