java juc包概述

1 atomic包

核心是CAS,主要提供了一系列原子变量更新操作的类,提供非阻塞式算法基础。

java juc包概述_第1张图片

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);
    }
}

2 locks包

java juc包概述_第2张图片
 主要提供了显示锁,如重入锁(ReentrantLock)和读写锁(ReadWriteLock)。核心是AQS这个抽象队列同步器框架。J.U.C包中很多工具类都是基于AQS实现的,如 

java juc包概述_第3张图片

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 并发容器

java juc包概述_第4张图片

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;
}


所以这种数据结构,相对比较适合读多写少的操作,不然修改的开销会较大

4 执行框架与线程池

java juc包概述_第5张图片

callable与runnable与 futrueTask
实现线程池的8中方式
线程池的参数

5 并发工具类

java juc包概述_第6张图片

CounntDownLatch CAS+unsafe.park
CyclicBarrier ReentranLock+condition
Semaphore AQS 

类结构参考:https://blog.csdn.net/sixabs/article/details/98471709

你可能感兴趣的:(java多线程)