核心是CAS,主要提供了一系列原子变量更新操作的类,提供非阻塞式算法基础。
AtomicLong的原理 value(valatile)+valueOffset+Unsafe
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicLong.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
public final long incrementAndGet() {
return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;
}
AtomicLongArray的原理和使用场景
与AtoicLong一样,但是获取偏移值的方式比较复杂
public final long incrementAndGet(int i) {
return getAndAdd(i, 1) + 1;
}
public final long getAndAdd(int i, long delta) {
return unsafe.getAndAddLong(array, checkedByteOffset(i), delta);
}
AtomicLongFiledUpdater
AtomicLongFieldUpdater value = AtomicLongFieldUpdater.newUpdater(DeathlockTest.class, "value");
public static AtomicLongFieldUpdater newUpdater(Class tclass,
String fieldName) {
Class> caller = Reflection.getCallerClass();
if (AtomicLong.VM_SUPPORTS_LONG_CAS)
return new CASUpdater(tclass, fieldName, caller);
else
return new LockedUpdater(tclass, fieldName, caller);
}
public long incrementAndGet(T obj) {
long prev, next;
do {
prev = get(obj);
next = prev + 1;
} while (!compareAndSet(obj, prev, next));
return next;
}
// 以CASUpdater为例
public final boolean compareAndSet(T obj, long expect, long update) {
accessCheck(obj);
return U.compareAndSwapLong(obj, offset, expect, update);
}
AtomicReferennce value(valatile)+valueOffset+Unsafe
public final V getAndSet(V newValue) {
return (V)unsafe.getAndSetObject(this, valueOffset, newValue);
}
LongAdder cells(Striped64)+CAS +volatile,适用于锁竞争很激烈场景
public void increment() {
add(1L);
}
public void add(long x) {
Cell[] as; long b, v; int m; Cell a;
if ((as = cells) != null || !casBase(b = base, b + x)) {
boolean uncontended = true;
if (as == null || (m = as.length - 1) < 0 ||
(a = as[getProbe() & m]) == null ||
!(uncontended = a.cas(v = a.value, v + x)))
longAccumulate(x, null, uncontended);
}
}
主要提供了显示锁,如重入锁(ReentrantLock)和读写锁(ReadWriteLock)。核心是AQS这个抽象队列同步器框架。J.U.C包中很多工具类都是基于AQS实现的,如
ReentrantLock AQS( CAS.state + queue)
ReentranReadWriteLock ( CAS + state + queue) state高读低写
多个读线程同时持有读锁(只要写锁未被占用),而写锁是独占的,支持重入。
Stampedlock 读写使用state不同部分 AQS
通过使用乐观读锁,在读的时候如果发生了写,应该通过重试的方式来获取新的值,而不应该阻塞写操作。
乐观锁:本质上未使用任何锁,只是获取操作前的stamp,用于在操作完成后校验操作期间是否发生了写,是的话需要重试。
//乐观读锁的使用
double distanceFromOrigin() {
long stamp = stampedLock.tryOptimisticRead(); //获得一个乐观读锁
double currentX = x;
double currentY = y;
if (!stampedLock.validate(stamp)) { //检查乐观读锁后是否有其他写锁发生,有则返回false;
//如果true,即无写锁发生,则不进入if内部,整个过程未使用锁
stamp = stampedLock.readLock(); //上面有写锁发生,需要获取一个悲观读锁
try {
currentX = x;
currentY = y;
} finally {
stampedLock.unlockRead(stamp); //释放悲观读锁
}
}
return Math.sqrt(currentX*currentX + currentY*currentY);
}
Stampedlock原理
state 64位 初始为 0001 0000 0000;
前7位(1-7位,2的0次幂开始)表示读,每获取一个读锁则加1;
别的位用来表示写,每获取一次写锁,加1000 0000,每次释放写锁再加一次1000 0000;
第一次获取写锁:
0001 0000 0000 + 0000 1000 0000 = 0001 1000 0000
第一次释放写锁:
0001 1000 0000 + 0000 1000 0000 = 0010 0000 0000
第二次获取写锁:
0010 0000 0000 + 0000 1000 0000 = 0010 1000 0000
第二次释放写锁:
0010 1000 0000 + 0000 1000 0000 = 0011 0000 0000
第n次获取写锁:
1110 0000 0000 + 0000 1000 0000 = 1110 1000 0000
第n次释放写锁:
1110 1000 0000 + 0000 1000 0000 = 1111 0000 0000
可以看到第8位在获取和释放写锁时会产生变化,也就是说第8位是用来表示写锁状态的,前7位是用来表示读锁状态的,8位之后是用来表示写锁的获取次数的
获取锁得到邮编(stamp),释放锁需要带上邮编stamp
参考:https://zhuanlan.zhihu.com/p/45323907
3 并发容器
ConcurrentLinkedQueue queue+NODE+CAS(用于节点的替换)
SynchronousQueue CAS put必须take,否则阻塞
CopyOnWriteArraySet CopyOnWriteArrayList+Lock
ConcurrentHashMap CAS
LinkedBlockingQueue ReentranLock+condition
ArrayBlockingQUeue ReentranLock+condition
CopyOnWrite 到底是什么意思呢?它的原理是,任何改,如 add、set、remove,都会拷贝原数组,修改后替换原来的数组,通过这种防御性的方式,实现另类的线程安全。如下代码:
public boolean add(E e) {
synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
// 拷贝
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
// 替换
setArray(newElements);
return true;
}
}
final void setArray(Object[] a) {
array = a;
}
所以这种数据结构,相对比较适合读多写少的操作,不然修改的开销会较大
callable与runnable与 futrueTask
实现线程池的8中方式
线程池的参数
CounntDownLatch CAS+unsafe.park
CyclicBarrier ReentranLock+condition
Semaphore AQS
类结构参考:https://blog.csdn.net/sixabs/article/details/98471709