亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

java并發(fā)之ArrayBlockingQueue詳細(xì)介紹

 更新時(shí)間:2017年05月22日 11:07:12   投稿:lqh  
這篇文章主要介紹了java并發(fā)之ArrayBlockingQueue詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下

java并發(fā)之ArrayBlockingQueue詳細(xì)介紹

 ArrayBlockingQueue是常用的線程集合,在線程池中也常常被當(dāng)做任務(wù)隊(duì)列來(lái)使用。使用頻率特別高。他是維護(hù)的是一個(gè)循環(huán)隊(duì)列(基于數(shù)組實(shí)現(xiàn)),循環(huán)結(jié)構(gòu)在數(shù)據(jù)結(jié)構(gòu)中比較常見(jiàn),但是在源碼實(shí)現(xiàn)中還是比較少見(jiàn)的。

線程安全的實(shí)現(xiàn)

      線程安全隊(duì)列,基本是離不開(kāi)鎖的。ArrayBlockingQueue使用的是ReentrantLock,配合兩種Condition,實(shí)現(xiàn)了集合的線程安全操作。這里稍微說(shuō)一個(gè)好習(xí)慣,下面是成員變量的聲明。

 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;

        賦值的操作基本都是在構(gòu)造函數(shù)里做的。這樣有個(gè)好處,代碼執(zhí)行可控。成員變量的初始化也是會(huì)合并在構(gòu)造方法里執(zhí)行的,但是在執(zhí)行順序上需要好好斟酌,如果寫(xiě)在構(gòu)造方法里初始化,則沒(méi)有相關(guān)問(wèn)題。

        阻塞隊(duì)列的常用場(chǎng)所就是生產(chǎn)者消費(fèi)者。一般都是生產(chǎn)者放入,消費(fèi)者從頭取數(shù)據(jù)。下面重點(diǎn)說(shuō)這兩個(gè)操作。

        這兩個(gè)操作都是依靠鎖來(lái)保證線程安全的。

生產(chǎn)操作

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等放入操作,首先是獲取鎖,如果發(fā)現(xiàn)數(shù)據(jù)滿了,就通過(guò)notFull的condition,來(lái)阻塞線程。這里的條件判定一定是用while而不是if,多線程情況下,可以被喚醒后發(fā)現(xiàn)又滿了。

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

        這個(gè)是入隊(duì)列的操作。首先獲取維護(hù)的數(shù)組。putindex就是放入操作的標(biāo)志。這個(gè)操作會(huì)一直加。達(dá)到預(yù)定的長(zhǎng)度后就變成0從頭開(kāi)始計(jì)數(shù)。這樣插入的操作就是一個(gè)循環(huán)的操作了,count就是用來(lái)做計(jì)數(shù)的,作為能否插入數(shù)據(jù)的一個(gè)標(biāo)準(zhǔn),插入數(shù)據(jù)后就通過(guò)notEmpty的condition發(fā)出一個(gè)信號(hào)喚醒消費(fèi)線程。

消費(fèi)操作

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

        消費(fèi)的方法也是這樣。先獲取鎖,然后進(jìn)行條件判斷,如果沒(méi)有數(shù)據(jù),則阻塞線程。注意點(diǎn)和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;
  }

        取數(shù)據(jù)的時(shí)候,也依靠takeIndex,這是一個(gè)標(biāo)志,這個(gè)數(shù)值也會(huì)一直增加,表示取的第一個(gè)數(shù)據(jù)的位置。如果這個(gè)標(biāo)志走到最后,然后變成0,從頭再來(lái)。這樣保證取出的數(shù)據(jù)都是fifo的順序。刪除的時(shí)候如果發(fā)現(xiàn)迭代中,則會(huì)修改迭代器的遍歷。然后通過(guò)notFull的condition來(lái)喚醒生產(chǎn)線程。

移除操作

 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();
    }
  }

        對(duì)于remove操作就比較麻煩了,首先獲取鎖之后,把兩個(gè)標(biāo)志位本地化,然后找到要?jiǎng)h除的元素的位置。調(diào)用removeAt,這里刪除需要對(duì)標(biāo)志位做改變。  

 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一樣。那就可以直接刪除,然后讓刪除標(biāo)志位向后移動(dòng)。如果不是,則從刪除的位置開(kāi)始,進(jìn)行后面向前面的數(shù)據(jù)覆蓋的操作。直到遇到putindex的前一個(gè)位置。然后把那個(gè)位置的數(shù)據(jù)設(shè)置為null。并且把putindex的位置往前移動(dòng)一格,正在迭代的時(shí)候要?jiǎng)h除數(shù)據(jù)并且喚醒生產(chǎn)線程。

        感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

相關(guān)文章

  • Java二維數(shù)組簡(jiǎn)單定義與使用方法示例

    Java二維數(shù)組簡(jiǎn)單定義與使用方法示例

    這篇文章主要介紹了Java二維數(shù)組簡(jiǎn)單定義與使用方法,結(jié)合實(shí)例形式簡(jiǎn)單分析了java二維數(shù)組的定義、使用方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2017-10-10
  • 如何基于回調(diào)實(shí)現(xiàn)Java的異步調(diào)用

    如何基于回調(diào)實(shí)現(xiàn)Java的異步調(diào)用

    這篇文章主要介紹了如何基于回調(diào)實(shí)現(xiàn)Java的異步調(diào)用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Java OpenCV4.0.0實(shí)現(xiàn)實(shí)時(shí)人臉識(shí)別

    Java OpenCV4.0.0實(shí)現(xiàn)實(shí)時(shí)人臉識(shí)別

    這篇文章主要為大家詳細(xì)介紹了Java OpenCV4.0.0實(shí)現(xiàn)實(shí)時(shí)人臉識(shí)別,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • 簡(jiǎn)單談?wù)刯ava中匿名內(nèi)部類構(gòu)造函數(shù)

    簡(jiǎn)單談?wù)刯ava中匿名內(nèi)部類構(gòu)造函數(shù)

    這篇文章主要簡(jiǎn)單給我們介紹了java中匿名內(nèi)部類構(gòu)造函數(shù),并附上了簡(jiǎn)單的示例,有需要的小伙伴可以參考下。
    2015-11-11
  • Springboot幾種任務(wù)的整合方法

    Springboot幾種任務(wù)的整合方法

    這篇文章主要介紹了Springboot幾種任務(wù)的整合方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • JAVA--HashMap熱門(mén)面試題

    JAVA--HashMap熱門(mén)面試題

    這篇文章主要介紹了JAVA關(guān)于HashMap容易被提問(wèn)的面試題,文中題目提問(wèn)頻率高,相信對(duì)你的面試有一定幫助,想要入職JAVA的朋友可以了解下
    2020-06-06
  • log4j的配置文件詳細(xì)解析

    log4j的配置文件詳細(xì)解析

    以下小編主要為大家介紹一下log4j的配置文件各個(gè)配置項(xiàng)的含義。需要的朋友可以過(guò)來(lái)參考下
    2013-08-08
  • Spring Boot Dubbo 構(gòu)建分布式服務(wù)的方法

    Spring Boot Dubbo 構(gòu)建分布式服務(wù)的方法

    這篇文章主要介紹了Spring Boot Dubbo 構(gòu)建分布式服務(wù)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-05-05
  • 詳解JAVA 七種創(chuàng)建單例的方法

    詳解JAVA 七種創(chuàng)建單例的方法

    這篇文章主要介紹了詳解JAVA 七種創(chuàng)建單例的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • swing重繪按鈕為任意形狀圖案的方法

    swing重繪按鈕為任意形狀圖案的方法

    這篇文章主要為大家詳細(xì)介紹了swing重繪按鈕為任意形狀圖案,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12

最新評(píng)論