老熟女激烈的高潮_日韩一级黄色录像_亚洲1区2区3区视频_精品少妇一区二区三区在线播放_国产欧美日产久久_午夜福利精品导航凹凸

深入淺析java并發中的ArrayBlockingQueue

這期內容當中小編將會給大家帶來有關深入淺析java并發中的ArrayBlockingQueue,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

創新互聯專注于企業營銷型網站建設、網站重做改版、平遙網站定制設計、自適應品牌網站建設、H5高端網站建設成都做商城網站、集團公司官網建設、成都外貿網站制作、高端網站制作、響應式網頁設計等建站業務,價格優惠性價比高,為平遙等各大城市提供網站開發制作服務。

java并發之ArrayBlockingQueue詳細介紹

 ArrayBlockingQueue是常用的線程集合,在線程池中也常常被當做任務隊列來使用。使用頻率特別高。他是維護的是一個循環隊列(基于數組實現),循環結構在數據結構中比較常見,但是在源碼實現中還是比較少見的。

線程安全的實現

      線程安全隊列,基本是離不開鎖的。ArrayBlockingQueue使用的是ReentrantLock,配合兩種Condition,實現了集合的線程安全操作。這里稍微說一個好習慣,下面是成員變量的聲明。

 private static final long serialVersionUID = -817911632652898426L;
  final Object[] items;
  int takeIndex;
  int putIndex;
  int count;
  final ReentrantLock lock;
  private final Condition notEmpty;
  private final Condition notFull;
  transient Itrs itrs = null;

        賦值的操作基本都是在構造函數里做的。這樣有個好處,代碼執行可控。成員變量的初始化也是會合并在構造方法里執行的,但是在執行順序上需要好好斟酌,如果寫在構造方法里初始化,則沒有相關問題。

        阻塞隊列的常用場所就是生產者消費者。一般都是生產者放入,消費者從頭取數據。下面重點說這兩個操作。

        這兩個操作都是依靠鎖來保證線程安全的。

生產操作

public void put(E e) throws InterruptedException {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
      while (count == items.length)
        notFull.await();
      enqueue(e);
    } finally {
      lock.unlock();
    }
  }

        put等放入操作,首先是獲取鎖,如果發現數據滿了,就通過notFull的condition,來阻塞線程。這里的條件判定一定是用while而不是if,多線程情況下,可以被喚醒后發現又滿了。

private void enqueue(E x) {
    final Object[] items = this.items;
    items[putIndex] = x;
    if (++putIndex == items.length)
      putIndex = 0;
    count++;
    notEmpty.signal();
  }

        這個是入隊列的操作。首先獲取維護的數組。putindex就是放入操作的標志。這個操作會一直加。達到預定的長度后就變成0從頭開始計數。這樣插入的操作就是一個循環的操作了,count就是用來做計數的,作為能否插入數據的一個標準,插入數據后就通過notEmpty的condition發出一個信號喚醒消費線程。

消費操作

 public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
      while (count == 0)
        notEmpty.await();
      return dequeue();
    } finally {
      lock.unlock();
    }
  }

        消費的方法也是這樣。先獲取鎖,然后進行條件判斷,如果沒有數據,則阻塞線程。注意點和put一樣。 

  private E dequeue() {
    final Object[] items = this.items;
    @SuppressWarnings("unchecked")
    E x = (E) items[takeIndex];
    items[takeIndex] = null;
    if (++takeIndex == items.length)
      takeIndex = 0;
    count--;
    if (itrs != null)
      itrs.elementDequeued();
    notFull.signal();
    return x;
  }

        取數據的時候,也依靠takeIndex,這是一個標志,這個數值也會一直增加,表示取的第一個數據的位置。如果這個標志走到最后,然后變成0,從頭再來。這樣保證取出的數據都是fifo的順序。刪除的時候如果發現迭代中,則會修改迭代器的遍歷。然后通過notFull的condition來喚醒生產線程。

移除操作

 public boolean remove(Object o) {
    if (o == null) return false;
    final Object[] items = this.items;
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
      if (count > 0) {
        final int putIndex = this.putIndex;
        int i = takeIndex;
        do {
          if (o.equals(items[i])) {
            removeAt(i);
            return true;
          }
          if (++i == items.length)
            i = 0;
        } while (i != putIndex);
      }
      return false;
    } finally {
      lock.unlock();
    }
  }

        對于remove操作就比較麻煩了,首先獲取鎖之后,把兩個標志位本地化,然后找到要刪除的元素的位置。調用removeAt,這里刪除需要對標志位做改變。  

 void removeAt(final int removeIndex) {
    final Object[] items = this.items;
    if (removeIndex == takeIndex) {
      items[takeIndex] = null;
      if (++takeIndex == items.length)
        takeIndex = 0;
      count--;
      if (itrs != null)
        itrs.elementDequeued();
    } else {
      final int putIndex = this.putIndex;
      for (int i = removeIndex;;) {
        int next = i + 1;
        if (next == items.length)
          next = 0;
        if (next != putIndex) {
          items[i] = items[next];
          i = next;
        } else {
          items[i] = null;
          this.putIndex = i;
          break;
        }
      }
      count--;
      if (itrs != null)
        itrs.removedAt(removeIndex);
    }
    notFull.signal();
  }

        如果刪除的元素是位置和takeindex一樣。那就可以直接刪除,然后讓刪除標志位向后移動。如果不是,則從刪除的位置開始,進行后面向前面的數據覆蓋的操作。直到遇到putindex的前一個位置。然后把那個位置的數據設置為null。并且把putindex的位置往前移動一格,正在迭代的時候要刪除數據并且喚醒生產線程。

上述就是小編為大家分享的深入淺析java并發中的ArrayBlockingQueue了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注創新互聯行業資訊頻道。


文章題目:深入淺析java并發中的ArrayBlockingQueue
網頁路徑:http://www.xueling.net.cn/article/joigsp.html

其他資訊

在線咨詢
服務熱線
服務熱線:028-86922220
TOP
主站蜘蛛池模板: 国产男女性潮高清免费网站 | 日日噜噜噜夜夜爽爽 | 色欲av久久无码影院色戒 | 国产资源视频在线观看 | 成人3dh动漫在线播放网站 | 国产精品一区二区在线免费观看 | 黄肉视频 | 日韩精品久久久久久免费 | 国产精品白浆无码流出.在线观看 | 国产乱人视频在线播放 | 一级生性活片免费视频片 | 91精品中文字幕一区二区三区 | 伊人久久大香线蕉综合啪小说 | 中文天堂网www新版资源在线 | 蜜桃无码AV一区二区 | 成人一级免费视频 | 人妻系列,一区二区三区 | 无码成人AAAAA毛片专区调教 | 一本一本久久A久久精品综合不卡 | 成人特级片 | 丰满少妇人妻久久久久久 | 视频1区2区3区 | 日本黄色免费看 | 久久中文综合 | 国产精品毛片无遮挡 | 韩国19禁无遮挡啪啪无码网站 | 久热综合在线亚洲精品 | 中文字幕亚洲欧美在线不卡 | 噜妇插内射精品 | 天海翼三点刺激高潮不停 | 亚洲精品久久国产精品37P | 欧美精品在线不卡 | 日日日对白普通话 | 日日摸日日碰夜夜爽亚洲精品蜜乳 | 奇米影视7777久久精品人人爽 | 精品a级片 | 国产性色一区二区 | www.国产精彩视频 | 日本在线不卡一区二区三区 | 久久精品噜噜噜成人av农村 | 成人在线观看91 |