CopyOnWriteArrayList集合:
使用ReentrantLock进行加锁是为了保证原子性
使用volatile修饰的数组是为了保证可见性和禁止指令重排序但是不能保证原子性
final transient ReentrantLock lock=new ReentrantLock();//可重入锁
private transient volatile Object[] array;//用volatile修饰的数组
volatile保证可见性和禁止重排序不能保证原子性,多个线程对Object数组进行操作时,不能保证线程安全。但是CopyOnWriteArrayList中有一个ReentrantLock,
ReentrantLock是用AQS实现的互斥锁(排他锁,独占锁)。当代码出现一些不可保证原子性操作的时候,可以使用ReentrantLock进行加锁,在加锁的这段你代码,它是线程安全的,又通过volatile数组保证可见性,锁住一段代码,对volatile数组修改以后立刻就会让其它线程可见
CopyOnWriteArrayList
add方法
public boolean add(E e) {
final ReentrantLock lock = this.lock;
//加锁
lock.lock();
try {
//获取底层数组
Object[] elements = getArray();
//数组的长度
int len = elements.length;
//拷贝一个新的数组,长度为元数组长度+1
Object[] newElements = Arrays.copyOf(elements, len + 1);
//新数组的最后一个位置插入的元素e
newElements[len] = e;
//修改数组引用
setArray(newElements);
//返回添加成功
return true;
} finally {
lock.unlock();
}
}
重载的add方法(可以在指定的位置添加元素)
public void add(int index, E element) {
final ReentrantLock lock = this.lock;
//加锁
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
if (index > len || index < 0)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+len);
Object[] newElements;
//插入元素时需要移动元素的个数
int numMoved = len - index;
//如果是在list的末尾插入元素
if (numMoved == 0)
newElements = Arrays.copyOf(elements, len + 1);
else {
//如果不是在list的末尾插入元素
newElements = new Object[len + 1]; //创建一个长度比原来大1的数组
System.arraycopy(elements, 0, newElements, 0, index);//将原来老数组的元素从0到index,拷贝到新数组中
System.arraycopy(elements, index, newElements, index + 1, numMoved);//将原来数组中index,index+1的元素,拷贝到新数组中
}
newElements[index] = element;//将index位置的元素设置为新元素
setArray(newElements);
} finally {
//解锁
lock.unlock();
}
}
set()方法
public E set(int index, E element) {
final ReentrantLock lock = this.lock;
//加锁
lock.lock();
try {
Object[] elements = getArray();
E oldValue = get(elements, index);
if (oldValue != element) {
int len = elements.length;
//拷贝新数组
Object[] newElements = Arrays.copyOf(elements, len);
//更新index元素值
newElements[index] = element;
//修改底层数组的引用
setArray(newElements);
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} 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);
int numMoved = len - index - 1;//移动元素的个数
//如果删除的是list最后一个元素
if (numMoved == 0)
setArray(Arrays.copyOf(elements, len - 1));
else {
//如果删除的不是list最后一个元素
Object[] newElements = new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index + 1, newElements, index,
numMoved);
setArray(newElements);
}
return oldValue;
} finally {
lock.unlock();
}
}
重载的remove()方法
public boolean remove(Object o) {
//获取原来的数组
Object[] snapshot = getArray();
//查询要删除的元素的位置
int index = indexOf(o, snapshot, 0, snapshot.length);
//调用重载的remove()方法删除元素
return (index < 0) ? false : remove(o, snapshot, index);
}
get()方法
public E get(int index) {
//返回index位置的元素
return get(getArray(), index);
}
Indexof()方法
public int indexOf(Object o) {
Object[] elements = getArray();
//调用重载的私有的indexOf()方法
return indexOf(o, elements, 0, elements.length);
}
//重载的私有的indexOf()方法
private static int indexOf(Object o, Object[] elements,
int index, int fence) {// o代表要查找的元素 elements底层的数组 index元素所在的位置 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;
}
CopyOnWriteArrayList在写入元素的时候需要拷贝数组,内存中会有两个数组,一个新数组,一个老数组,将老数组的数据拷贝到新数组中,修改底层数组array(用voliate修饰)的引用让其他的线程知道
HashMap
JDK1.7 HashMap是由一维数组组成,一维数组里面存放的是一维键值对的对象
时间复杂度
通过链表的方式解决hash碰撞,把hash值相等的元素通过链表的方式存储
当hash表的容量到达一维数组长度的75%,就会触发扩容,扩容后的hash表与原来的hash表相比容量翻了一倍
HshMap可以存储key为null的键值对吗?
放在table[0]这个位置
HashMap的容量为什么是2的整次方?
N mod 2 的整次方==N & (2的整次方-1)
计算机底层对于位运算符效率更高