The second concurrent programming of the JUC

3.2 StampedLock

Since JDK8 join the class, in order to further optimize read performance, which is characterized by using a read lock, write lock must cooperate [stamp] use
plus interpretation lock
Here Insert Picture Description
locked write lock
Here Insert Picture Description
optimistic locking, StampedLock support tryOptimisticRead () method (optimistic reading ), after finished reading need to do a poke check If the check does not indicate a write operation during this period, the data can be used safely, if the check does not pass, you need to re-acquire a read lock to ensure data security.
Here Insert Picture Description

4. Semaphore

Semaphores, threads used to restrict access to both the upper limit of shared resources.
Here Insert Picture Description

Semaphore principle

  1. Lock unlock process
    Semaphore bit like a parking lot, just like the number of parking permits, obtain permits when the thread is like to get a parking space, and then display the parking lot of free parking spaces minus a
    beginning, permits (state) 3, which 5 threads to access resources
    Here Insert Picture Description
    hypothesis which thread - 1, thread - 2, thread -4 cas compete successfully, and thread - 0 and thread - 3 competition fails, AQS queue to enter the park blocked
    Here Insert Picture Description
    this time thread - 4 release of the permits, state follows
    Here Insert Picture Description
    next Thread - 0 of competition success, permits again set to 0, set Thread himself as head node, disconnect your old head node, unpark next --3 node, but the permits are 0, Thread - 3 try not after successfully entering the state park again
    Here Insert Picture Description

5. CountdownLatch

用来进行线程同步协作,等待所有线程完成倒计时。
其中构造参数用来初始化等待计数值,await()用来等待计数归零,countDown()用来让计数减一

6. CyclicBarrier

循环栅栏,用来进行线程协作,等待线程满足某个计数。构造时设置【计数个数】,每个线程执行到某个需要“同步”的时刻调用await()方法进行等待,当等待的线程数满足【计数个数】时,继续执行
Here Insert Picture Description

7.线程安全集合类概述

Here Insert Picture Description
线程安全集合类可以分为三大类 :

  • 遗留的线程安全集合如 Hashtable、Vector
  • 使用Collections装饰的线程安全集合,如 :
    • Collections.synchronizedCollection
    • Collections.synchronizedList
    • Collections.synchronizedMap
    • Collections.synchronizedSet
    • Collections.synchronizedNavigableMap
    • Collections.synchronizedNavigableSet
    • Collections.synchronizedMap
    • Collections.synchronizedSet
  • java.util.concurrent.*
    重点介绍java.util.concurrent.*下的线程安全集合类,里面包含三类关键词 :Blocking、CopyOnWrite、Concurrent
  • Blocking大部分实现基于锁,并提供用来阻塞的方法
  • CopyOnWrite 之类容器修改稍相对较重
  • Concurrent类型的容器
    • 内部很多操作使用cas优化,一般可以提供高吞吐量
    • 弱一致性
      • 遍历时弱一致性,例如,当利用迭代器遍历时,如果容器发生修改,迭代器任然可以进行进行遍历,这时内存是旧的
      • 求大小弱一致性,size操作未必是100%准确
      • 读取弱一致性
  • 遍历时如果发生了修改,对于非安全容器来讲,使用fail-fast机制也就是让遍历立刻失败,抛出ConcurrentModificationExecption,不再继续遍历

8. ConcurrentHashMap

单词计数问题 :
Here Insert Picture Description
Here Insert Picture Description
重要属性和内部类
Here Insert Picture Description
构造器分析
可以看到实现了懒惰初始化,在构造方法中仅仅计算了table的大小,以后在第一次使用时才会真正的创建
Here Insert Picture Description
get流程分析
Here Insert Picture Description
put流程
以下数组简称(table),链表简称(bin)
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
size计算流程
size计算实际发生在put、remove改变集合元素的操作之中

  • 没有竞争发生,向baseCount累加计数
  • 有竞争发生,新建counterCells,向其中的一个cell累加计数
    • counterCells初始有两个cell
    • 如果计数竞争比较激烈,会创建新的cell来累加计数
      Here Insert Picture Description

3. JDK7 ConcurrentHashMap

它维护了一个segment数组,每个segment对应一把锁

  • 优点 : 如果多个线程访问不同的segment,实际是没有冲突的,这与jdk8中是类似的
  • 缺点 :Segments数组默认大小为16,这个容量初始化指定后就不能改变了,并且不是懒得初始化
    构造器分析
    Here Insert Picture Description
    Here Insert Picture Description
    可以看到ConcurrentHashMap 没有实现懒惰初始化,空间占用不友好
    其中 this.segmentShift 和 this.segmentMask的作用是决定将key的hash结果匹配到那个 segment
    例如 :根据某一hash值求segment位置,先将高位向低位移动 this.segmentShift位
    Here Insert Picture Description
    结果再与this.segmentMask 做位于运算,最终得到1010即下标为10的segment
    Here Insert Picture Description
    put流程
    Here Insert Picture Description
    segment继承了可重入锁(ReentrantLock),它的put方法为
    Here Insert Picture Description
    Here Insert Picture Description
    Here Insert Picture Description
    get流程
    get时并未加锁,用了UNSAFE方法保证了可见性,扩容过程中,get先发生就从旧表取内容,get后发生就从新表取内容
    Here Insert Picture Description
    size计算流程
  • 计算元素个数前,先不加锁计算两次,如果前后两次结果如一样,认为个数正确返回
  • 如果不一样,进行重试,重试次数超过3,将所有segment锁住,重新计算个数返回
    Here Insert Picture Description
    Here Insert Picture Description
    Here Insert Picture Description
    LinkedBlockingQueue 原理
  1. 基本的入队出队
    Here Insert Picture Description
    初始化链表 last = head = new Node(null);Dummy节点用来占位,item为null
    Here Insert Picture Description
    当一个节点入队 last = last.next = node;
    Here Insert Picture Description
    再来一个节点入队 last = last.next = node
    Here Insert Picture Description
    出队
    Here Insert Picture Description
    h = head
    Here Insert Picture Description
    first = h.next
    Here Insert Picture Description
    h.next = h
    Here Insert Picture Description
    head = first
    Here Insert Picture Description
    E x = first.item;
    first.item = null;
    return x;
    Here Insert Picture Description
  2. 加锁分析
    高明之处在于用了两把锁和dummy节点
  • 用一把锁,同一时刻,最多只允许有一个线程(生产者或消费者,二选一)执行
  • 用两把锁,同一时刻,可以允许两个线程同时(一个生产者与一个消费者)执行
    • 消费者与消费者线程任然串行
    • 生产者与生产者线程任然串行
      线程安全分析
  • 当节点总数大于2时(包括dummy节点),putLock保证的是last节点的线程安全,takeLock保证的是head节点的线程安全。两把锁保证了入队和出队没有竞争
  • 当节点总数等于2时(即一个dummy节点,一个正常节点)这时候,仍然是两把锁锁两个对象,不会竞争
  • 当节点总数等于1时(就一个dummy节点)这时take线程会被notEmpty条件阻塞,有竞争,会阻塞
    Here Insert Picture Description
    put操作
    Here Insert Picture Description
    take操作
    Here Insert Picture Description

3. 性能比较

主要列举 LinkedBlockingQueue与ArrayBlockingQueue的性能比较

  • Linked支持有界,Array强制有界
  • Linked实现是链表,Array实现是数组
  • Linked lazy, and Node Array need to initialize the array in advance
  • Linked into each team will generate a new Node, and Array of Node is to create good advance
  • Linked two locks, Array a lock

10. ConcurrentLinkedQueue

ConcurrentLinkedQueue design and LinkedBlockingQueue very much like, but also

  • Two [lock], the same time, allows two threads (a producer and a consumer) execution
  • Introducing dummy node lock to make two [future] is locked different objects, to avoid competition
  • Only this cas [lock] used to achieve
    in fact, still very wide range of applications ConcurrentLinkedQueue
    example, before talking about the structure of Tomcat Connector, Acceptor as producers deliver event information to consumers when Poller, it uses ConcurrentLinkedQueue to the SocketChannel Poller use

11. CopyOnWriteArrayList

CopyOnWriteArraySet vest its
underlying implementation uses a copy writing idea underlying array CRUD operations will copy, change operation performed on the new array, then it does not affect the reading of other concurrent threads, separate read and write.
Here Insert Picture Description
Here's the source code version Java11, used in Java1.8 is reentrant lock and not synchronized, other read operations are not locked, for example:
Here Insert Picture Description
for reading and writing [less] application scenarios
get weakly consistent
Here Insert Picture Description
Here Insert Picture Description
iterator weak consistency
Here Insert Picture Description
Do not feel bad weak consistency

  • MVCC database is weak consistency of performance
  • High concurrency and consistency is contradictory, need to weigh

Guess you like

Origin www.cnblogs.com/haizai/p/12360857.html