吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 952|回复: 3
收起左侧

[讨论] JUC

[复制链接]
tomcar 发表于 2021-8-31 20:13
1、Unsafe mechanics代码中CAS经常用到的,以ConcurrentHashMap中的为例
[Java] 纯文本查看 复制代码
// 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、属性            
[Java] 纯文本查看 复制代码
   /** * 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、内部类
[Java] 纯文本查看 复制代码
                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方法           
[Java] 纯文本查看 复制代码
     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时的初始化方法            
[Java] 纯文本查看 复制代码
    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<?,?>[n];
                    table = tab = nt;
                    sc = n - (n >>> 2);
                }
            } finally {
                sizeCtl = sc;
            }
            break;
        }
    }
    return tab;
}
              
treeifyBin 链表转红黑树            
[Java] 纯文本查看 复制代码
   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 扩容方法         
[Java] 纯文本查看 复制代码
       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<?,?>[n];
                        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,用于处理高并发问题   
[Java] 纯文本查看 复制代码
             // 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方法            
[Java] 纯文本查看 复制代码
   // 比较基础,遍历查找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方法           
[Java] 纯文本查看 复制代码
     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、属性            
[Java] 纯文本查看 复制代码
   /**
 * 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、内部类              
[Java] 纯文本查看 复制代码
  private static class Node<E>{}private class Itr implements Iterator<E> {}
static final class CLQSpliterator<E> implements Spliterator<E> {}
              
3.3、offer方法            
[Java] 纯文本查看 复制代码
   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
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 22:35

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表