tomcar 发表于 2021-8-31 20:13

JUC

1、Unsafe mechanics代码中CAS经常用到的,以ConcurrentHashMap中的为例// Unsafe mechanics
private static final sun.misc.Unsafe U;
private static final long SIZECTL;
private static final long TRANSFERINDEX;
private static final long BASECOUNT;
private static final long CELLSBUSY;
private static final long CELLVALUE;
private static final long ABASE;
private static final int ASHIFT;

static {
    try {
      U = sun.misc.Unsafe.getUnsafe();
      Class<?> k = ConcurrentHashMap.class;
      SIZECTL = U.objectFieldOffset
            (k.getDeclaredField("sizeCtl"));
      TRANSFERINDEX = U.objectFieldOffset
            (k.getDeclaredField("transferIndex"));
      BASECOUNT = U.objectFieldOffset
            (k.getDeclaredField("baseCount"));
      CELLSBUSY = U.objectFieldOffset
            (k.getDeclaredField("cellsBusy"));
      Class<?> ck = CounterCell.class;
      CELLVALUE = U.objectFieldOffset
            (ck.getDeclaredField("value"));
      Class<?> ak = Node[].class;
      ABASE = U.arrayBaseOffset(ak);
      int scale = U.arrayIndexScale(ak);
      if ((scale & (scale - 1)) != 0)
            throw new Error("data type scale not a power of two");
      ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
    } catch (Exception e) {
      throw new Error(e);
    }
}            2、ConcurrentHashMap   2.1、属性                /** * The array of bins. Lazily initialized upon first insertion.
* Size is always a power of two. Accessed directly by iterators.
*/
transient volatile Node<K,V>[] table;

/**
* The next table to use; non-null only while resizing.
*/
private transient volatile Node<K,V>[] nextTable;

/**
* Base counter value, used mainly when there is no contention,
* but also as a fallback during table initialization
* races. Updated via CAS.
*/
private transient volatile long baseCount;

/**
* Table initialization and resizing control.When negative, the
* table is being initialized or resized: -1 for initialization,
* else -(1 + the number of active resizing threads).Otherwise,
* when table is null, holds the initial table size to use upon
* creation, or 0 for default. After initialization, holds the
* next element count value upon which to resize the table.
*/
private transient volatile int sizeCtl;

/**
* The next table index (plus one) to split while resizing.
*/
private transient volatile int transferIndex;

/**
* Spinlock (locked via CAS) used when resizing and/or creating CounterCells.
*/
private transient volatile int cellsBusy;

/**
* Table of counter cells. When non-null, size is a power of 2.
*/
private transient volatile CounterCell[] counterCells;

// views
private transient KeySetView<K,V> keySet;
private transient ValuesView<K,V> values;
private transient EntrySetView<K,V> entrySet;
...
            2.2、内部类
                static class Node<K,V> implements Map.Entry<K,V> {}
static class Segment<K,V> extends ReentrantLock implements Serializable {}
static final class ForwardingNode<K,V> extends Node<K,V> {}
static final class ReservationNode<K,V> extends Node<K,V> {}
@sun.misc.Contended static final class CounterCell {}
static final class TreeNode<K,V> extends Node<K,V> {}
static final class TreeBin<K,V> extends Node<K,V> {}
static final class TableStack<K,V> {}
static class Traverser<K,V> {}
static class BaseIterator<K,V> extends Traverser<K,V> {}
static final class KeyIterator<K,V> extends BaseIterator<K,V> implements Iterator<K>, Enumeration<K> {}
static final class ValueIterator<K,V> extends BaseIterator<K,V> implements Iterator<V>, Enumeration<V> {}
static final class EntryIterator<K,V> extends BaseIterator<K,V> implements Iterator<Map.Entry<K,V>> {}
static final class MapEntry<K,V> implements Map.Entry<K,V> {}
static final class KeySpliterator<K,V> extends Traverser<K,V> implements Spliterator<K> {}
static final class ValueSpliterator<K,V> extends Traverser<K,V> implements Spliterator<V> {}
static final class EntrySpliterator<K,V> extends Traverser<K,V> implements Spliterator<Map.Entry<K,V>> {}
abstract static class CollectionView<K,V,E> implements Collection<E>, java.io.Serializable {}
public static class KeySetView<K,V> extends CollectionView<K,V,K> implements Set<K>, java.io.Serializable {}
static final class ValuesView<K,V> extends CollectionView<K,V,V> implements Collection<V>, java.io.Serializable {}
static final class EntrySetView<K,V> extends CollectionView<K,V,Map.Entry<K,V>> implements Set<Map.Entry<K,V>>, java.io.Serializable {}
abstract static class BulkTask<K,V,R> extends CountedCompleter<R> {}
...
            2.3、put方法            public V put(K key, V value) {
    return putVal(key, value, false);
}

/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
    if (key == null || value == null) throw new NullPointerException();
    // 散列较高位的hash值,分散数据
    int hash = spread(key.hashCode());   // return (h ^ (h >>> 16)) & HASH_BITS;static final int HASH_BITS = 0x7fffffff;第一位是0,hash值都是正数
    int binCount = 0;
    for (Node<K,V>[] tab = table;;) {
      Node<K,V> f; int n, i, fh;
      // 如果table为空时,先初始化table,initTable方法如下方代码
      if (tab == null || (n = tab.length) == 0)tab = initTable();
      else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
            // 通过cas初始化第一个Node节点具体实现:return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
            if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null)))break;   // no lock when adding to empty bin
      // hash是负的,是在扩容的时候出现的               
      } else if ((fh = f.hash) == MOVED)tab = helpTransfer(tab, f);
      else { // f是该位置的头节点,并且不为空
            V oldVal = null;
            // 拿每一个Node作为锁
            synchronized (f) {
                // 与前面9行比较下,防止多线程造成的线程不安全
                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是一个TreeBin(红黑树) ,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) {
                // 判断是否要将链表转换为红黑树,临界值和 HashMap 一样,也是 8
                if (binCount >= TREEIFY_THRESHOLD)
                        // 这个方法和 HashMap 中稍微有一点点不同,那就是它不是一定会进行红黑树转换,
                   // 如果当前数组的长度小于 64,那么会选择进行数组扩容,而不是转换为红黑树
                  treeifyBin(tab, i);
                if (oldVal != null)
                  return oldVal;
                break;
            }
      }
    }
    addCount(1L, binCount);
    return null;
}            put时的初始化方法                private final Node<K,V>[] initTable() {    Node<K,V>[] tab; int sc;
    while ((tab = table) == null || tab.length == 0) {
      if ((sc = sizeCtl) < 0)
            Thread.yield(); // lost initialization race; just spin   场景:两个线程时,第二个线程如果取到是-1,就让出cpu,此时如果另一个线程没有插入值时,会一直循环让出cpu,直到另一个线程将size变更,然后会跳出到上一层,进行插入操作
      else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {    // 场景,两个线程时,第一个线程会先cas将sc改为-1,第二个线程取到就是-1   SIZECTL:是个偏移量,通过偏移量修改的数据,保证一致性
            try {
                if ((tab = table) == null || tab.length == 0) {
                  int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                  @SuppressWarnings("unchecked")
                  Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>;
                  table = tab = nt;
                  sc = n - (n >>> 2);
                }
            } finally {
                sizeCtl = sc;
            }
            break;
      }
    }
    return tab;
}
            treeifyBin 链表转红黑树                private final void treeifyBin(Node<K,V>[] tab, int index) {
    Node<K,V> b; int n, sc;
    if (tab != null) {
      if ((n = tab.length) < MIN_TREEIFY_CAPACITY)   // 如果小于临界值64,则扩容
            tryPresize(n << 1);
      else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
            // 锁 Node节点
            synchronized (b) {
                // 再次确认一下,该节点没有被修改
                if (tabAt(tab, index) == b) {
                  TreeNode<K,V> hd = null, tl = null;
                  for (Node<K,V> e = b; e != null; e = e.next) {
                        TreeNode<K,V> p =
                            new TreeNode<K,V>(e.hash, e.key, e.val,
                                              null, null);
                        if ((p.prev = tl) == null)
                            hd = p;
                        else
                            tl.next = p;
                        tl = p;
                  }
                  setTabAt(tab, index, new TreeBin<K,V>(hd));
                }
            }
      }
    }
}            tryPresize 扩容方法                private final void tryPresize(int size) {
    int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
      tableSizeFor(size + (size >>> 1) + 1);
    int sc;
    while ((sc = sizeCtl) >= 0) {
      Node<K,V>[] tab = table; int n;
      if (tab == null || (n = tab.length) == 0) {
            n = (sc > c) ? sc : c;
            if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                try {
                  if (table == tab) {
                        @SuppressWarnings("unchecked")
                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>;
                        table = nt;
                        sc = n - (n >>> 2);
                  }
                } finally {
                  sizeCtl = sc;
                }
            }
      }
      else if (c <= sc || n >= MAXIMUM_CAPACITY)
            break;
      else if (tab == table) {
            int rs = resizeStamp(n);
            if (sc < 0) {
                Node<K,V>[] nt;
                if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                  sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                  transferIndex <= 0)
                  break;
                if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
                  transfer(tab, nt);
            }
            else if (U.compareAndSwapInt(this, SIZECTL, sc,
                                       (rs << RESIZE_STAMP_SHIFT) + 2))
                transfer(tab, null);
      }
    }
}            ConcurrentHashMap中的Unsafe,用于处理高并发问题                // Unsafe mechanics
private static final sun.misc.Unsafe U;
private static final long SIZECTL;
private static final long TRANSFERINDEX;
private static final long BASECOUNT;
private static final long CELLSBUSY;
private static final long CELLVALUE;
private static final long ABASE;
private static final int ASHIFT;
static {
    try {
      U = sun.misc.Unsafe.getUnsafe();
      Class<?> k = ConcurrentHashMap.class;
      SIZECTL = U.objectFieldOffset(k.getDeclaredField("sizeCtl"));
      TRANSFERINDEX = U.objectFieldOffset(k.getDeclaredField("transferIndex"));
      BASECOUNT = U.objectFieldOffset(k.getDeclaredField("baseCount"));
      CELLSBUSY = U.objectFieldOffset(k.getDeclaredField("cellsBusy"));
      Class<?> ck = CounterCell.class;
      CELLVALUE = U.objectFieldOffset(ck.getDeclaredField("value"));
      Class<?> ak = Node[].class;
      ABASE = U.arrayBaseOffset(ak);
      int scale = U.arrayIndexScale(ak);
      if ((scale & (scale - 1)) != 0)throw new Error("data type scale not a power of two");
      ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
    } catch (Exception e) {
      throw new Error(e);
    }
}            2.4、get方法                // 比较基础,遍历查找public V get(Object key) {
    Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
    int h = spread(key.hashCode());
    if ((tab = table) != null && (n = tab.length) > 0 &&
      (e = tabAt(tab, (n - 1) & h)) != null) {
      if ((eh = e.hash) == h) {
            if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                return e.val;
      }
      else if (eh < 0)
            return (p = e.find(h, key)) != null ? p.val : null;
      while ((e = e.next) != null) {
            if (e.hash == h &&
                ((ek = e.key) == key || (ek != null && key.equals(ek))))
                return e.val;
      }
    }
    return null;
}
            2.5、containsValue方法            public boolean containsValue(Object value) {    if (value == null)
      throw new NullPointerException();
    Node<K,V>[] t;
    if ((t = table) != null) {
      // 包装成了一个内部类的方式
      Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
      // advance 方法,向前遍历,具体实现在下方
      for (Node<K,V> p; (p = it.advance()) != null; ) {
            V v;
            if ((v = p.val) == value || (v != null && value.equals(v)))
                return true;
      }
    }
    return false;
}
            
Traverser.advance()

                /**
* Advances if possible, returning next valid node, or null if none.
*/
final Node<K,V> advance() {
    Node<K,V> e;
    if ((e = next) != null)
      e = e.next;
    for (;;) {
      Node<K,V>[] t; int i, n;// must use locals in checks
      if (e != null)
            return next = e;
      if (baseIndex >= baseLimit || (t = tab) == null ||
            (n = t.length) <= (i = index) || i < 0)
            return next = null;                        // 这块是遍历结束了,没有查询到值,返回了
      if ((e = tabAt(t, i)) != null && e.hash < 0) {   // CAS通过偏移量直接去取内存中的值
            if (e instanceof ForwardingNode) {
                tab = ((ForwardingNode<K,V>)e).nextTable;
                e = null;
                pushState(t, i, n);
                continue;
            }
            else if (e instanceof TreeBin)
                e = ((TreeBin<K,V>)e).first;
            else
                e = null;
      }
      if (stack != null)
            recoverState(n);
      else if ((index = i + baseSize) >= n)
            index = ++baseIndex; // visit upper slots if present
    }
}
            3、ConcurrentLinkedQueue3.1、属性                /**
* A node from which the first live (non-deleted) node (if any)
* can be reached in O(1) time.
* Invariants:
* - all live nodes are reachable from head via succ()
* - head != null
* - (tmp = head).next != tmp || tmp != head
* Non-invariants:
* - head.item may or may not be null.
* - it is permitted for tail to lag behind head, that is, for tail
*   to not be reachable from head!
*/
private transient volatile Node<E> head;
/**
* A node from which the last node on list (that is, the unique
* node with node.next == null) can be reached in O(1) time.
* Invariants:
* - the last node is always reachable from tail via succ()
* - tail != null
* Non-invariants:
* - tail.item may or may not be null.
* - it is permitted for tail to lag behind head, that is, for tail
*   to not be reachable from head!
* - tail.next may or may not be self-pointing to tail.
*/
private transient volatile Node<E> tail;            3.2、内部类            private static class Node<E>{}private class Itr implements Iterator<E> {}
static final class CLQSpliterator<E> implements Spliterator<E> {}
            3.3、offer方法                public boolean offer(E e) {
    checkNotNull(e);
    final Node<E> newNode = new Node<E>(e);

    for (Node<E> t = tail, p = t;;) {
      Node<E> q = p.next;
      if (q == null) {
            // p is last node
            if (p.casNext(null, newNode)) {
                // Successful CAS is the linearization point
                // for e to become an element of this queue,
                // and for newNode to become "live".
                if (p != t) // hop two nodes at a time
                  casTail(t, newNode);// Failure is OK.
                return true;
            }
            // Lost CAS race to another thread; re-read next
      }
      else if (p == q)
            // We have fallen off list.If tail is unchanged, it
            // will also be off-list, in which case we need to
            // jump to head, from which all live nodes are always
            // reachable.Else the new tail is a better bet.
            p = (t != (t = tail)) ? t : head;
      else
            // Check for tail updates after two hops.
            p = (p != t && t != (t = tail)) ? t : q;
    }
}            

chenbaofa 发表于 2021-8-31 20:57

用原子类手写个自选锁就好,

JinxBoy 发表于 2021-8-31 22:03

感谢分享

lyj996 发表于 2021-8-31 23:18

学习了,感谢分享
页: [1]
查看完整版本: JUC