• 并发(3) 容器


      容器类中提供的ArrayList、HashMap、HashSet不是线程安全的,并发包下提供了类似功能的线程安全的集合。

    说明 原理
    ConcurrentHashMap    
    ConcurrentSkipListMap    
    ConcurrentSkipListSet    
    CopyOnWriteArrayList    
    CopyOnWriteArraySet    

      队列是一种数据结构,它以一种先进先出的方式管理数据。如果你试图向一个 已经满了的阻塞队列中添加一个元素或者是从一个空的阻塞队列中移除一个元索,将导致线程阻塞。

    队列操作:

    方法  说明
    boolean add(E e)  添加一个元素到队列中,如果队列已满,则抛出异常
    E remove() 移除并返回队列头部的元素,如果队列为空,则抛出异常
    E element() 返回队列头部的元素,如果队列为空,则抛出异常
    boolean offer(E e) 添加一个元素到队列中,如果队列已满,返回false
    offer(E e, long timeout, TimeUnit unit) 添加一个元素到队列中,等待指定时间,如果队列已满,返回false
    E poll() 移除并返回队列头部的元素,如果队列为空,返回null
    E poll(long timeout, TimeUnit unit) 移除并返回队列头部的元素,等待指定时间,如果队列为空,返回null
    E peek() 返回队列头部的元素,如果队列为空,返回null
    void put(E e) 返回队列头部的元素,如果队列已满,阻塞
    E take() 移除并返回队列头部的元素,如果队列为空,阻塞

    数组实现

    ArrayBlockingQueue

      Qeueu的数组实现,底层使用一个数组实现,数组大小不可变,使用一个count表示当前元素个数,使用putIndex表示当前尾的index,使用takeIndex表示当前头的index,putindex不一定比takeindex大,是在数组连续的循环。使用一个ReentrantLock控制读写并发。使用两个Condition来阻塞数组为空时消费或者数组满时生产的线程,当数组中有数据或者有空间时唤醒。迭代器中使用一个index指向下一个元素位置;

      1 public class ArrayBlockingQueue<E> extends AbstractQueue<E>
      2         implements BlockingQueue<E>, java.io.Serializable {
      3 
      4     //存储数据数组
      5     final Object[] items;
      6     //头index
      7     int takeIndex;
      8     //尾index
      9     int putIndex;
     10     //队列长度
     11     int count;
     12     //
     13     final ReentrantLock lock;
     14     //非空条件
     15     private final Condition notEmpty;
     16     //非满条件
     17     private final Condition notFull;
     18     //初始化
     19     public ArrayBlockingQueue(int capacity) {
     20         this(capacity, false);
     21     }
     22     public ArrayBlockingQueue(int capacity, boolean fair) {
     23         if (capacity <= 0)
     24             throw new IllegalArgumentException();
     25         this.items = new Object[capacity];
     26         lock = new ReentrantLock(fair);
     27         notEmpty = lock.newCondition();
     28         notFull =  lock.newCondition();
     29     }
     30     public ArrayBlockingQueue(int capacity, boolean fair,
     31                               Collection<? extends E> c) {
     32         this(capacity, fair);
     33 
     34         final ReentrantLock lock = this.lock;
     35         lock.lock(); // Lock only for visibility, not mutual exclusion
     36         try {
     37             int i = 0;
     38             try {
     39                 for (E e : c) {
     40                     checkNotNull(e);
     41                     items[i++] = e;
     42                 }
     43             } catch (ArrayIndexOutOfBoundsException ex) {
     44                 throw new IllegalArgumentException();
     45             }
     46             count = i;
     47             putIndex = (i == capacity) ? 0 : i;
     48         } finally {
     49             lock.unlock();
     50         }
     51     }
     52     //新增一个元素
     53     public boolean add(E e) {
     54         return super.add(e);
     55     }
     56 
     57     //新增一个元素
     58     public boolean offer(E e) {
     59         checkNotNull(e);
     60         final ReentrantLock lock = this.lock;
     61         lock.lock();
     62         try {
     63             //如果已满,返回false,否则添加到队列中
     64             if (count == items.length)
     65                 return false;
     66             else {
     67                 enqueue(e);
     68                 return true;
     69             }
     70         } finally {
     71             lock.unlock();
     72         }
     73     }
     74     //新增一个元素
     75     public void put(E e) throws InterruptedException {
     76         checkNotNull(e);
     77         final ReentrantLock lock = this.lock;
     78         lock.lockInterruptibly();
     79         try {
     80             //如果已满,等待,否则添加到队列中
     81             while (count == items.length)
     82                 notFull.await();
     83             enqueue(e);
     84         } finally {
     85             lock.unlock();
     86         }
     87     }
     88     //添加一个元素
     89     private void enqueue(E x) {
     90         final Object[] items = this.items;
     91         items[putIndex] = x;
     92         if (++putIndex == items.length)
     93             putIndex = 0;
     94         count++;
     95         notEmpty.signal();
     96     }
     97     //获取头部元素
     98     public E poll() {
     99         final ReentrantLock lock = this.lock;
    100         lock.lock();
    101         try {
    102             //如果为空返回null,否则返回头部元素
    103             return (count == 0) ? null : dequeue();
    104         } finally {
    105             lock.unlock();
    106         }
    107     }
    108     //获取头部元素
    109     public E take() throws InterruptedException {
    110         final ReentrantLock lock = this.lock;
    111         lock.lockInterruptibly();
    112         try {
    113             //如果为空阻塞,否则返回头部元素
    114             while (count == 0)
    115                 notEmpty.await();
    116             return dequeue();
    117         } finally {
    118             lock.unlock();
    119         }
    120     }
    121     //获取头部元素
    122     private E dequeue() {
    123         // assert lock.getHoldCount() == 1;
    124         // assert items[takeIndex] != null;
    125         final Object[] items = this.items;
    126         @SuppressWarnings("unchecked")
    127         E x = (E) items[takeIndex];
    128         items[takeIndex] = null;
    129         if (++takeIndex == items.length)
    130             takeIndex = 0;
    131         count--;
    132         if (itrs != null)
    133             itrs.elementDequeued();
    134         notFull.signal();
    135         return x;
    136     }
    137 }
    View Code

    LinkedBlockingQueue

      Qeueu的列表实现,底层使用一个单向链表实现。大小可变也可以设定大小。使用一个节点作为头节点,不存储数据;使用一个节点作为尾节点,存储数据,使用两个ReentrantLock分别控制读写锁,头节点不存储数据也是避免读写并发冲突,count使用了原子变量也是为了避免读写冲突。

      因为使用了读写锁,所以吞吐量要比ArrayBlockingQueue好。对内存和GC的影响会大于ArrayBlockingQueue。

      1 public class LinkedBlockingQueue<E> extends AbstractQueue<E>
      2         implements BlockingQueue<E>, java.io.Serializable {
      3     private static final long serialVersionUID = -6903933977591709194L;
      4     //链表节点
      5     static class Node<E> {
      6         E item;
      7 
      8         /**
      9          * One of:
     10          * - the real successor Node
     11          * - this Node, meaning the successor is head.next
     12          * - null, meaning there is no successor (this is the last node)
     13          */
     14         Node<E> next;
     15 
     16         Node(E x) { item = x; }
     17     }
     18     //队列容量
     19     private final int capacity;
     20     //队列元素个数
     21     private final AtomicInteger count = new AtomicInteger();
     22     //头节点
     23     transient Node<E> head;
     24     //尾节点
     25     private transient Node<E> last;
     26     //取数据锁
     27     private final ReentrantLock takeLock = new ReentrantLock();
     28     
     29     private final Condition notEmpty = takeLock.newCondition();
     30     //存数据锁
     31     private final ReentrantLock putLock = new ReentrantLock();
     32 
     33     private final Condition notFull = putLock.newCondition();
     34     
     35     public LinkedBlockingQueue() {
     36         this(Integer.MAX_VALUE);
     37     }
     38 
     39     public LinkedBlockingQueue(int capacity) {
     40         if (capacity <= 0) throw new IllegalArgumentException();
     41         this.capacity = capacity;
     42         last = head = new Node<E>(null);
     43     }
     44     //存放元素
     45     public void put(E e) throws InterruptedException {
     46         if (e == null) throw new NullPointerException();
     47         int c = -1;
     48         Node<E> node = new Node<E>(e);
     49         final ReentrantLock putLock = this.putLock;
     50         final AtomicInteger count = this.count;
     51         putLock.lockInterruptibly();
     52         try {
     53             //如果到达容量,则等待
     54             while (count.get() == capacity) {
     55                 notFull.await();
     56             }
     57             enqueue(node);
     58             c = count.getAndIncrement();
     59             if (c + 1 < capacity)
     60                 notFull.signal();
     61         } finally {
     62             putLock.unlock();
     63         }
     64         if (c == 0)
     65             signalNotEmpty();
     66     }
     67     
     68     //存放元素
     69     public boolean offer(E e) {
     70         if (e == null) throw new NullPointerException();
     71         final AtomicInteger count = this.count;
     72         if (count.get() == capacity)
     73             return false;
     74         int c = -1;
     75         Node<E> node = new Node<E>(e);
     76         final ReentrantLock putLock = this.putLock;
     77         putLock.lock();
     78         try {
     79             //如果到达容量,返回false
     80             if (count.get() < capacity) {
     81                 enqueue(node);
     82                 c = count.getAndIncrement();
     83                 if (c + 1 < capacity)
     84                     notFull.signal();
     85             }
     86         } finally {
     87             putLock.unlock();
     88         }
     89         if (c == 0)
     90             signalNotEmpty();
     91         return c >= 0;
     92     }
     93     private void enqueue(Node<E> node) {
     94         // assert putLock.isHeldByCurrentThread();
     95         // assert last.next == null;
     96         last = last.next = node;
     97     }
     98     //获取元素
     99     public E take() throws InterruptedException {
    100         E x;
    101         int c = -1;
    102         final AtomicInteger count = this.count;
    103         final ReentrantLock takeLock = this.takeLock;
    104         takeLock.lockInterruptibly();
    105         try {
    106             //如果队列为空,则等待
    107             while (count.get() == 0) {
    108                 notEmpty.await();
    109             }
    110             x = dequeue();
    111             c = count.getAndDecrement();
    112             if (c > 1)
    113                 notEmpty.signal();
    114         } finally {
    115             takeLock.unlock();
    116         }
    117         if (c == capacity)
    118             signalNotFull();
    119         return x;
    120     }
    121     //获取元素
    122     public E poll() {
    123         final AtomicInteger count = this.count;
    124         if (count.get() == 0)
    125             return null;
    126         E x = null;
    127         int c = -1;
    128         final ReentrantLock takeLock = this.takeLock;
    129         takeLock.lock();
    130         try {
    131             //如果队列为空,返回null
    132             if (count.get() > 0) {
    133                 x = dequeue();
    134                 c = count.getAndDecrement();
    135                 if (c > 1)
    136                     notEmpty.signal();
    137             }
    138         } finally {
    139             takeLock.unlock();
    140         }
    141         if (c == capacity)
    142             signalNotFull();
    143         return x;
    144     }
    145     private E dequeue() {
    146         // assert takeLock.isHeldByCurrentThread();
    147         // assert head.item == null;
    148         Node<E> h = head;
    149         Node<E> first = h.next;
    150         h.next = h; // help GC
    151         head = first;
    152         E x = first.item;
    153         first.item = null;
    154         return x;
    155     }
    156     //获取元素
    157     public E peek() {
    158         if (count.get() == 0)
    159             return null;
    160         final ReentrantLock takeLock = this.takeLock;
    161         takeLock.lock();
    162         try {
    163             Node<E> first = head.next;
    164             if (first == null)
    165                 return null;
    166             else
    167                 return first.item;
    168         } finally {
    169             takeLock.unlock();
    170         }
    171     }
    172 }
    View Code

    SynchronousQueue

      

    PriorityBlockingQueue

      优先级队列,按照自定义的优先级顺序进行读取。底层使用一个数组实现二叉堆。大小可变且无边界。

    DelayQueue

      延时队列,底层使用一个PriorityQueue实现,使用一个ReentrantLock控制并发。其实就是在每次往优先级队列中添加元素,然后以元素的delay/过期值作为排序的因素,以此来达到先过期的元素会拍在队首,每次从队列里取出来都是最先要过期的元素

      1 public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
      2         implements BlockingQueue<E> {
      3 
      4     private final transient ReentrantLock lock = new ReentrantLock();
      5     private final PriorityQueue<E> q = new PriorityQueue<E>();
      6     private Thread leader = null;
      7     private final Condition available = lock.newCondition();
      8 
      9     public DelayQueue() {}
     10     //向队列中添加元素,因为是无边界队列,所以不会抛异常
     11     public boolean add(E e) {
     12         return offer(e);
     13     }
     14     //向队列中添加元素
     15     public boolean offer(E e) {
     16         final ReentrantLock lock = this.lock;
     17         lock.lock();
     18         try {
     19             q.offer(e);
     20             if (q.peek() == e) {
     21                 leader = null;
     22                 available.signal();
     23             }
     24             return true;
     25         } finally {
     26             lock.unlock();
     27         }
     28     }
     29     //向队列中添加元素,因为是无边界队列,所以不会阻塞
     30     public void put(E e) {
     31         offer(e);
     32     }
     33     //从队列总获取数据
     34     public E poll() {
     35         final ReentrantLock lock = this.lock;
     36         lock.lock();
     37         try {
     38             E first = q.peek();
     39             if (first == null || first.getDelay(NANOSECONDS) > 0)
     40                 return null;
     41             else
     42                 return q.poll();
     43         } finally {
     44             lock.unlock();
     45         }
     46     }
     47     //从队列总获取数据,如果队列为空,则阻塞
     48     public E take() throws InterruptedException {
     49         final ReentrantLock lock = this.lock;
     50         lock.lockInterruptibly();
     51         try {
     52             for (;;) {
     53                 E first = q.peek();
     54                 if (first == null)
     55                     available.await();
     56                 else {
     57                     long delay = first.getDelay(NANOSECONDS);
     58                     if (delay <= 0)
     59                         return q.poll();
     60                     first = null; // don't retain ref while waiting
     61                     if (leader != null)
     62                         available.await();
     63                     else {
     64                         Thread thisThread = Thread.currentThread();
     65                         leader = thisThread;
     66                         try {
     67                             available.awaitNanos(delay);
     68                         } finally {
     69                             if (leader == thisThread)
     70                                 leader = null;
     71                         }
     72                     }
     73                 }
     74             }
     75         } finally {
     76             if (leader == null && q.peek() != null)
     77                 available.signal();
     78             lock.unlock();
     79         }
     80     }
     81 
     82     public E poll(long timeout, TimeUnit unit) throws InterruptedException {
     83         long nanos = unit.toNanos(timeout);
     84         final ReentrantLock lock = this.lock;
     85         lock.lockInterruptibly();
     86         try {
     87             for (;;) {
     88                 E first = q.peek();
     89                 if (first == null) {
     90                     if (nanos <= 0)
     91                         return null;
     92                     else
     93                         nanos = available.awaitNanos(nanos);
     94                 } else {
     95                     long delay = first.getDelay(NANOSECONDS);
     96                     if (delay <= 0)
     97                         return q.poll();
     98                     if (nanos <= 0)
     99                         return null;
    100                     first = null; // don't retain ref while waiting
    101                     if (nanos < delay || leader != null)
    102                         nanos = available.awaitNanos(nanos);
    103                     else {
    104                         Thread thisThread = Thread.currentThread();
    105                         leader = thisThread;
    106                         try {
    107                             long timeLeft = available.awaitNanos(delay);
    108                             nanos -= delay - timeLeft;
    109                         } finally {
    110                             if (leader == thisThread)
    111                                 leader = null;
    112                         }
    113                     }
    114                 }
    115             }
    116         } finally {
    117             if (leader == null && q.peek() != null)
    118                 available.signal();
    119             lock.unlock();
    120         }
    121     }
    122     //
    123     public E peek() {
    124         final ReentrantLock lock = this.lock;
    125         lock.lock();
    126         try {
    127             return q.peek();
    128         } finally {
    129             lock.unlock();
    130         }
    131     }
    132 
    133 
    134 }
    View Code
  • 相关阅读:
    ***EF中的问题(复习的同学可略过)
    课堂练习
    MVC-07 案例2
    MVC-06 安装部署
    MVC-05 Model(2)
    MVC-05 Model(1)
    MVC-04 视图(3)
    Learning Web
    MVC-04 视图(2)
    hdu 1272 并查集
  • 原文地址:https://www.cnblogs.com/zhangwanhua/p/9284741.html
Copyright © 2020-2023  润新知