RandomAccess接口
public interface RandomAccess {
}
RandomAccess是一个标志性接口,没有任何定义。标志实现这个接口的类具有随机访问的功能。
在binartSearch()
方法中,会判断传入的list是否RandomAccess实现
增删改都需要获得锁,并且锁只有一把,而读操作不需要获得锁,支持并发。
我知道Vector是增删改查方法都加了synchronized,保证同步,但是每个方法执行的时候都要去获得锁,性能就会大大下降,而CopyOnWriteArrayList 只是在增删改上加锁,但是读不加锁,在读方面的性能就好于Vector,CopyOnWriteArrayList支持读多写少的并发情况。
public class CopyOnWriteArraySet<E> extends AbstractSet<E>
implements java.io.Serializable {
private static final long serialVersionUID = 5457747651344034263L;
private final CopyOnWriteArrayList<E> al;
/**
* Creates an empty set.
*/
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
...
}
CopyOnWriteArraySet的底层存储结构竟然是CopyOnWriteArrayList,那么我们就可以知道它的名字的由来了,并且知道它支持并发的原理跟CopyOnWriteArrayList是一样的。
// 注意在hash过程中,会进处理。(h = key.hashCode()) ^ (h >>> 16); 相当于在散列过程中同时考虑高16位的信息
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
头插改成尾插的原因是:为了防止resize过程中形成循环链表
在hash的过程中,需要对size取模,而如果size的长度是,则可通过的计算方法得到。
创建Map过程中,初始的size不一定是, 如果不是,则会进行处理:
// 这是java11中的写法,与java8中有所不同
static final int tableSizeFor(int cap) {
int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
key如果为null,会默认将hash为0,hash后放在桶0中。
注意:在ConcurrentHashMap中是不能插入key为null的,ConcurrentHashMap不能put null 是因为 无法分辨是key没找到的null还是有key值为null,这在多线程里面是模糊不清的,所以压根就不让put null。
主要根据集合的特点来选?,?如我们需要根据键值获取到元素值时就选?Map接?下的集合,需要排序时选择TreeMap,不需要排序时就选择HashMap,需要保证线程安全就选?ConcurrentHashMap.当我们只 需要存放元素值时,就选择实现Collection接?的集合,需要保证元素唯?时选择实现Set接?的集合 ?如TreeSet或HashSet,不需要就选择实现List接?的?如ArrayList或LinkedList,然后再根据实现 这些接?的集合的特点来选?。
原文:https://www.cnblogs.com/yinjiacheng/p/14783048.html