基本的位操作
- 与( & )每一位进行比较,两位都为1,结果为1,否则为0(-4 & 1 = 0)
1 0 0 1 1 -->(19)[10] 表示10进制中的19
& 1 1 0 0 1 -->(25)[10]
1 0 0 0 1 -->(17)[10]
- 或( | )每一位进行比较,两位有一位是1,结果就是1(-4 | 1 = -3)
1 0 0 1 1 -->(19)[10]
| 1 1 0 0 1 -->(25)[10]
------------------------------
1 1 0 1 1 -->(27)[10]
- 非( ~ ) 每一位进行比较,按位取反(符号位也要取反)(~ -4 = 3)
~ 1 0 0 1 1 -->(19)[10]
-----------------------------
0 1 1 0 0 -->(12)[10]
- 异或( ^ )每一位进行比较,相同为0,不同为1(^ -4 = -3)
1 0 0 1 1 -->(19)[10]
^ 1 1 0 0 1 -->(25)[10]
-----------------------------
0 1 0 1 0 -->(10)[10]
- 左移( << ) 整体左移,右边空出位补零,左边位舍弃 (-4 << 1 = -8)
int a = 8;
a << 3;
移位前:0000 0000 0000 0000 0000 0000 0000 1000 -->(8)[10]
移位后:0000 0000 0000 0000 0000 0000 0100 0000 -->(64)[10] 相当于 X 2^3
- 右移( >> ) 整体右移,左边空出位补零或补1(负数补1,整数补0),右边位舍弃 (-4 >> 1 = -2)
unsigned int a = 8;
a >> 3;
移位前:0000 0000 0000 0000 0000 0000 0000 1000 -->(8)[10]
移位后:0000 0000 0000 0000 0000 0000 0000 0001 -->(1)[10] 相当于 / 2^3
int a = -8;
a >> 3;
移位前:1111 1111 1111 1111 1111 1111 1111 1000 -->(-8)[10]
移位前:1111 1111 1111 1111 1111 1111 1111 1111 -->(-1)[10]
- 无符号右移( >>> )同>>,但不管正数还是负数都左边位都补0 (-4 >>> 1 = 2147483646)
HashMap
构造方法中初始容量计算
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
初始容量不大于最大容量的情况下,返回大于输入参数且最接近2的整数次幂的数。比如输入10,返回16。
多次右移、或位运算后将n低位全置为1,返回n+1就为1个1后面全为0(10000),n+1用10进制就是2的整数次幂。
cap - 1:处理参数为2的整数次幂的情况。
ConcurrentHashMap
ConcurrentHashMap1.7使用分段锁;1.8使用 CAS+synchronized实现并发安全。
HashMap1.8扩容多线程会创建多个hashtable,ConcurrentHashMap1.8多线程会帮忙一起扩容。
final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {//多线程CAS算法
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
//table下标所在值为空,使用CAS将value插入,多线程时,其他线程会CAS插入失败,经过for循环走到下面if判断
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
//扩容时将节点置为ForwardingNode,此时hash为-1,等于MOVED
//另一个线程正在扩容,会帮忙扩容
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
//table下标所在值不为空,使用synchronized在f上加锁,插入链表,锁的是Bucket(链表/红黑树)
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key,
value, null);
break;
}
}
}
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
addCount(1L, binCount);
return null;
}