read t2 = new ChangeObjectThread("t2");
public static class ChangeObjectThread extends Thread {
public ChangeObjectThread(String name) {
super(name);
}
@Override
public void run() {
synchronized (u) {
System.out.println("in " + getName());
LockSupport.park();
}
}
}
public static void main(String[] args) throws InterruptedException {
t1.start();
Thread.sleep(100);
t2.start();
LockSupport.unpark(t1);
LockSupport.unpark(t2);
t1.join();
t2.join();
}
}
其本质是在读写map操作上都加了锁, 因此不推荐在高并发场景使用.
支持高并发的HashMap. 通过将一个大的hashmap切割成无数个小的分区hashmap(Segment<K,V>).
执行put的时候把key映射到其中一个小的分区中, 假如有十几个线程, 那么可能就会对应十几个分区.
public V put(K key, V value) {
ConcurrentHashMap.Segment<K,V> s;
if (value == null)
throw new NullPointerException();
int hash = hash(key);
int j = (hash >>> segmentShift) & segmentMask;
// 通过unsafe对j进行偏移来寻找key所对应的分区
if ((s = (ConcurrentHashMap.Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck
(segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment
// 如果分区不存在, 则创建新的分区
s = ensureSegment(j);
// kv放到分区中
return s.put(key, hash, value, false);
}
Segment.put源码
Segment(float lf, int threshold, ConcurrentHashMap.HashEntry<K,V>[] tab) {
this.loadFactor = lf;
this.threshold = threshold;
this.table = tab;
}
final V put(K key, int hash, V value, boolean onlyIfAbsent) {
// tryLock通过无锁cas操作尝试获取锁(无等待), 继承自ReentrantLock.
// 如果成功则, node = null
// 如果不成功, 则可能其他线程已经在插入数据了,
// 此时会尝试继续获取锁tryLock, 自旋MAX_SCAN_RETRIES次, 若还是拿不到锁才开始lock
ConcurrentHashMap.HashEntry<K,V> node = tryLock() ? null :
scanAndLockForPut(key, hash, value);
V oldValue;
try {
ConcurrentHashMap.HashEntry<K,V>[] tab = table;
// 获取分区中哪一个entry链的index
int index = (tab.length - 1) & hash;
// 获取第一个entry
ConcurrentH