Java基礎-2、併發

目錄

 

synchronized

Volatile

信號量Semaphore

實現所有線程在等待某個事件的發生纔去執行

CAS缺陷以及如何解決

AQS

死鎖、活鎖

線程池

線程池的種類

配置線程池大小

工作機制及原理

ThreadPoolExecutor類

ThreadLoad原理

LockSupport工具

Condition原理

Fork/Join框架的理解

分段鎖(JUC)的原理、鎖力度的減小思考

八種阻塞隊列以及各個阻塞隊列的特性


synchronized

class TestSynchronized{
    Object
lock = null;
   
public void method1(){
       
lock = new Object();
       
synchronized (lock){
            System.
out.println("----method1----");
        }
    }
   
public void method2(){
       
synchronized (this){
            System.
out.println("----method2----");
        }
    }
   
public synchronized void method3(){
        System.
out.println("----method3----");
    }
   
public static synchronized void method4(){
        System.
out.println("----method4----");
    }

}

 

 

類別

Synchronized

Lock

存在形式

JAVA關鍵字,JVM

是一個類

鎖的釋放

  1. 獲取鎖的線程執行完成同步中的代碼
  2. 線程發生異常

在finally中必須釋放鎖,不然會造成死鎖

獲取鎖

如果A線程獲取了鎖,那麼B線程等待。如果A線程阻塞,那麼B線程會一直等待

Lock有多種鎖的獲取方式,都可以嘗試獲得鎖,線程可以不用一直等待

鎖狀態

無法判斷

可判斷

鎖類型

悲觀鎖(可重入 不可中斷 非公平)

樂觀鎖(可重入 可判斷 可公平(兩者皆可))

性能

少量同步

大量同步

 

偏向鎖-》輕量級鎖-》重量級鎖(1.6後)

互斥鎖ReentrantLock

 

Volatile

volatile:用來修飾被不同線程訪問和修改的變量

volatile關鍵字與JVM內存模型相關

  Java語言是支持多線程的,爲了解決線程併發的問題,在語言內部引入了同步塊和volatile關鍵字機制

volatile關鍵字機制:

 synchronized修飾方法和代碼塊,以實現同步

 用volatile修飾的變量,線程在每次使用變量的時候,都會讀取變量修改後的值。volatile經常被誤用進行原子性的操作。但是這些操作並不是真正的原子性。在讀取加載之後,如果變量發生了變化,線程工作內存中的值由於已加載,不會產生對應的變法。對於volatile修改的變量,JVM只是保證從內存加載到線程工作內存的值是最新的。

交互圖:

public class VolatileTest {
    //public static int count = 0; //實際運算每次結果都不一樣
    public static volatile int count = 0; //
    public static void inc(){
        //這裏延遲1毫秒,使得結果明顯
        try {
            Thread.sleep(1);
        } catch (Exception e) {
            // TODO: handle exception
        }
        count ++;
    }
    
    public static void main(String[] args) {
        //同時啓動1000個線程,去進行i++運算,看看實際結果
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() { 
                @Override
                public void run() {
                    VolatileTest.inc();
                }
            }).start();
        }
        
        System.out.println("運行結果:"+count);
    }

}

 

信號量Semaphore

       在多線程中,線程間傳遞信號的一種方式。

       與互斥量的區別

  1. 互斥量用於線程的互斥,信號量用於線程的同步
  2. 互斥量值只能爲0/1,信號量值可以爲非負整數。信號量可以實現多個同類資源的多線程互斥和同步。
  3. 互斥量的加鎖和解鎖必須由同一線程分別對應使用,信號量可以由一個線程釋放,另一個線程得到。

class TestSemaphore{
    Semaphore
semaphore = new Semaphore(10);//控制10個共享資源的使用
   
public void use(){
       
try {
           
semaphore.acquire();
        }
catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
   
public  void  release(){
       
semaphore.release();
    }
}

 

實現所有線程在等待某個事件的發生纔去執行

1.閉鎖CountDownLatch

閉鎖是典型的等待事件發生的同步工具類,將閉鎖的初始值設置1,所有線程調用await方法等待,當事件發生時調用countDown將閉鎖值減爲0,則所有await等待閉鎖的線程得以繼續執行。

class TestCountDownLatch{
   
public static void main(String[] args){
       
int num = 2;
        final
CountDownLatch latch = new CountDownLatch(num);
        for
(;num> 0;num--){
           
new Thread(){
               
public void run() {
                   
try {
                        System.out.println(
"子線程"+Thread.currentThread().getName()+"正在執行");
                       
Thread.sleep(3000);
                       
System.out.println("子線程"+Thread.currentThread().getName()+"執行完畢");
                       
latch.countDown();
                   
} catch (InterruptedException e) {
                        e.printStackTrace()
;
                   
}
                }
;
           
}.start();
       
}
       
try {
            System.
out.println("等待2個子線程執行完畢...");
           
latch.await();
           
System.out.println("2個子線程已經執行完畢");
           
System.out.println("繼續執行主線程");
       
} catch (InterruptedException e) {
            e.printStackTrace()
;
       
}
    }
}

 

2.阻塞隊列BlockingQueue

所有等待事件的線程嘗試從空的阻塞隊列獲取元素,將阻塞,當事件發生時,向阻塞隊列中同時放入N個元素(N的值與等待的線程數相同),則所有等待的線程從阻塞隊列中取出元素後得以繼續執行。

 

3.信號量Semaphore

設置信號量的初始值爲等待的線程數N,一開始將信號量申請完,讓剩餘的信號量爲0,待事件發生時,同時釋放N個佔用的信號量,則等待信號量的所有線程將獲取信號量得以繼續執行。

class TestSemaphore{
   
public static void main(String[] args){
       
// 8位工人
       
int n = 8;
       
// 5臺機器
       
Semaphore semaphore = new Semaphore(5);
        for
(int i=0;i<n;i++){
           
new Worker(i,semaphore).start();
       
}
    }
   
static class Worker extends Thread{
       
private int num;
        private
Semaphore semaphore;
        public
Worker(int num,Semaphore semaphore){
           
this.num = num;
            this
.semaphore = semaphore;
       
}

       
@Override
       
public void run() {
           
try {
               
semaphore.acquire();
               
System.out.println("工人"+this.num+"佔用一個機器在生產...");
               
Thread.sleep(2000);
               
System.out.println("工人"+this.num+"釋放出機器");
               
semaphore.release();
           
} catch (InterruptedException e) {
                e.printStackTrace()
;
            
}
        }
    }
}

 

4.柵欄CyclicBarrier

設置柵欄的初始值爲1,當事件發生時,調用barrier.wait()衝破設置的柵欄,將調用指定的Runable線程執行,在該線程中啓動N個新的子線程執行。這個方法並不是讓執行中的線程全部等待在某個點,待某一事件發生後繼續執行。

class TestCyclicBarrier{
   
public static void main(String[] args) {
       
int N = 4;
       
CyclicBarrier barrier  = new CyclicBarrier(N);
        for
(int i=0;i<N;i++){
           
new Writer(barrier).start();
       
}
    }
   
static class Writer extends Thread{
       
private CyclicBarrier cyclicBarrier;
        public
Writer(CyclicBarrier cyclicBarrier) {
           
this.cyclicBarrier = cyclicBarrier;
       
}
       
@Override
       
public void run() {
            System.
out.println("線程"+Thread.currentThread().getName()+"正在寫入數據...");
            try
{
               
//以睡眠來模擬寫入數據操作
               
Thread.sleep(5000);
               
System.out.println("線程"+Thread.currentThread().getName()+"寫入數據完畢,等待其他線程寫入完畢");
               
cyclicBarrier.await();
           
} catch (InterruptedException e) {
                e.printStackTrace()
;
           
}catch(BrokenBarrierException e){
                e.printStackTrace()
;
           
}

            System.
out.println("所有線程寫入完畢,繼續處理其他任務...");
        
}
    }
}

 

CAS缺陷以及如何解決

參考地址:https://blog.csdn.net/jeffleo/article/details/75269618

CAS:Compare And Swap,即比較並交換。(AtomicInteger)

實現了Java多線程的併發操作。整個AQS同步組件、Atomic原子類操作等都是以CAS實現的,甚至ConcurrentHashMap在1.8的版本中也調整爲了CAS+Synchronized。可以說CAS是整個JUC的基石。

 

缺陷:

主要表現在三個方法:

循環時間太長

只能保證一個共享變量原子操作

ABA問題:解決方案則是版本號

AQS

       參考資料:https://www.cnblogs.com/daydaynobug/p/6752837.html

     AQS:AbstractQueuedSynchronized, 抽象的隊列式的同步器,AQS定義了一套多線程訪問共享資源的同步器框架,許多同步類實現都依賴於它,如常用的ReentrantLock/Semaphore/CountDownLatch

       AQS裏的state只有兩種狀態:0表示未鎖定,1表示鎖定

死鎖、活鎖

死鎖:指兩個或兩個以上的進程在執行過程中,由於競爭資源或者由於彼此通信而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。4個產生條件:

  1. 互斥條件
  2. 請求和保持條件
  3. 不剝奪條件
  4. 環路等待條件

活鎖:指的是任務或者執行者沒有被阻塞,由於某些條件沒有滿足,導致一直重複嘗試—失敗—嘗試—失敗的過程。處於活鎖的實體是在不斷的改變狀態,活鎖有可能自行解開。

線程池

資源地址:https://blog.csdn.net/wxq544483342/article/details/53118674  

線程池的種類

1、創建一個緩衝池,緩衝池容量大小爲Integer.MAX_VALUE

         ExecutorService pool = Executors.newCachedThreadPool();

2、創建容量爲1的緩衝池

        ExecutorService pool = Executors.newSingleThreadExecutor(); 

3、創建固定容量大小的緩衝池

ExecutorService pool = Executors.newFixedThreadPool(int);

4、創建一個定長線程池,支持定時及週期性任務執行。

         ExecutorService pool = Executors.newScheduledThreadPool(1);

5、創建一個擁有多個任務隊列(以便減少連接數)的線程池。

         ExecutorService pool = Executors.newWorkStealingPool();
ExecutorService類的方法:
void shutdown(); 
         關閉線程池 不可以再 submit 新的 task,已經 submit 的將繼續執行
         List<Runnable> shutdownNow();
         關閉線程池 試圖停止當前正在執行的 task,並返回尚未執行的 task 的 list
         boolean isShutdown();
         是否已經關閉了線程池,當調用shutdown()或shutdownNow()方法後返回爲true。 
         boolean isTerminated();
         當調用shutdown()方法後,並且所有提交的任務完成後返回爲true;

          當調用shutdownNow()方法後,成功停止後返回爲true;
         boolean awaitTermination(long timeout, TimeUnit unit) throws         InterruptedException;
         <T> Future<T> submit(Callable<T> task);
         <T> Future<T> submit(Runnable task, T result);
         Future<?> submit(Runnable task);
         <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)

         throws InterruptedException;
         <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,

                              long timeout, TimeUnit unit)

         throws InterruptedException;
         <T> T invokeAny(Collection<? extends Callable<T>> tasks)

         throws InterruptedException, ExecutionException;
         <T> T invokeAny(Collection<? extends Callable<T>> tasks,

                long timeout, TimeUnit unit)

         throws InterruptedException, ExecutionException, TimeoutException;

配置線程池大小

  1. CPU密集型任務,就需要儘量壓榨CPU,參考值可以設爲 NCPU+1
  2. IO密集型任務,參考值可以設置爲2*NCPU

工作機制及原理

線程池的兩個核心隊列:

  1. 線程等待池,即線程隊列BlockingQueue
  2. 任務處理池(PoolWorker),即正在工作的Thread列表(HashSet)

線程池的核心參數:

  1. 核心池大小(corePoolSize),即固定大小,設定好之後,線程池的穩定峯值,達到這個值之後池的線程數大小不會釋放。
  2. 最大處理線程池數(maximumPoolSize),當線程池裏面的線程數超過corePoolSize,小於maximumPoolSize時會動態創建與回收線池裏面的線程池資源。

ThreadPoolExecutor類

構造方法:

/**

 *

 * @param corePoolSize  核心池大小 默認情況下,在創建好線程池之後,線程池中的線程數爲0,當有任務來之後,就會創建一個線程去執行任務,

 *                      當線程池中的線程數量達到corePoolSize後,就會把這些任務放到緩存隊列中

 * @param maximumPoolSize 線程池最大線程數量,表示在線程池中最多能創建線程的數量;在corePoolSize和maximumPoolSize的線程數會被自動釋放,而小於corePoolSize的則不會。

 * @param keepAliveTime 表示線程沒有執行任務時最多保持多久時間會終止。

 *                      默認情況下,只有當線程池中的線程數大於corePoolSize時,keepAliveTime纔會生效,直到線程池數量不大於corePoolSize,

 *                      即只有當線程池數量大於corePoolSize數量,超出這個數量的線程一旦到達keepAliveTime就會終止。

 *                      但是如果調用了allowCoreThreadTimeout(boolean)方法,即使線程池的線程數量不大於corePoolSize,線程也會在keepAliveTime之後就終止,知道線程池的數量爲0爲止。

 * @param unit 參數keepAliveTime的時間單位,一個時間單位枚舉類。 Nanos/Micros/Millis/Seconds/Minutes/Hours/Days

 * @param workQueue 一個阻塞隊列,用來存儲等待執行任務的隊列,這個參數選擇也很重要,會對線程池的運行過程產生重大影響。

 *                  一般來說,這裏的阻塞隊列就是(ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue)。

 * @param threadFactory 線程工廠,主要用來創建線程;可以是一個自定義的線程工廠,默認就是Executors.defaultThreadFactory()。用來在線程池中創建線程。

 * @param handler 表示當拒絕處理任務時的策略,也是可以自定義的,默認是我們前面的4種取值:

 *                  ThreadPoolExecutor.AbortPolicy(默認的,一言不合即拋異常的)

 *                  ThreadPoolExecutor.DiscardPolicy(一言不合就丟棄任務)

 *                  ThreadPoolExecutor.DiscardOldestPolicy(一言不合就把最近的任務給拋棄,然後執行當前任務)

 *                  ThreadPoolExecutor.CallerRunsPolicy(由調用者所在線程來執行任務)

 */

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,

                             BlockingQueue<Runnable> workQueue, public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,

                             BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,RejectedExecutionHandler handler) {

        if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0)

            throw new IllegalArgumentException();

        if (workQueue == null || threadFactory == null || handler == null)

            throw new NullPointerException();

        this.corePoolSize = corePoolSize;

        this.maximumPoolSize = maximumPoolSize;

        this.workQueue = workQueue;

        this.keepAliveTime = unit.toNanos(keepAliveTime);

        this.threadFactory = threadFactory;

        this.handler = handler;

    }

 

ThreadLoad原理

class TestThreadLocal{
   
private static TestThreadLocal testThreadLocal = null;
   
private static ThreadLocal<TestThreadLocal> map = new ThreadLocal<TestThreadLocal>();
   
private TestThreadLocal(){}
   
public static synchronized TestThreadLocal getInstance1(){
       
if(testThreadLocal==null){
           
testThreadLocal = new TestThreadLocal();
        }
       
return testThreadLocal;
    }
   
public static TestThreadLocal getInstance2(){ //效率大於getInstance1()
       
testThreadLocal = map.get();
       
if(testThreadLocal==null){
           
testThreadLocal = new TestThreadLocal();
           
map.set(testThreadLocal);
        }
       
return testThreadLocal;
    }
}

 

LockSupport工具

LockSupport提供了park和unpark方法實現阻塞和解除阻塞,都是基於“許可(permit)”作爲關聯。permit相當於一個信號量(0,1),默認是0。

使用偏移量來獲取對象。是因爲線程已經被阻塞了,如果不通過內存的方式,直接調用線程內的方法,線程是不會響應的。

park()、unpark()和wait()、notify()的區別

  1. 面向的主體不同。LockSupport是針對Thread進行阻塞,可以指定阻塞的對象,每次可以喚醒指定具體的線程。Wait()是以對象,阻塞當前的線程和喚醒單個線程或者所有線程。
  2. 實現的機制不同。LockSupport可以指定monitor的object對象,但和object.wait()兩者的阻塞隊列並不交叉。

static void testLockSupport(){
   
// 調用native方法阻塞當前線程
   
LockSupport.park();
   
// 阻塞當前線程,最長不超過nanos納秒,返回條件在park()的基礎上增加了超時返回
   
LockSupport.parkNanos(1);
   
// 阻塞當前線程,知道deadline時間(deadline - 毫秒數)
   
LockSupport.parkUntil(1);

   
Object blocker = new Object();
   
//1) 記錄當前線程等待的對象(阻塞對象);
    //2) 阻塞當前線程;
    //3) 當前線程等待對象置爲null。
   
LockSupport.park(blocker);
   
// 阻塞當前線程,最長等待時間不超過nanos毫秒,同樣,在阻塞當前線程的時候做了記錄當前線程等待的對象操作
   
LockSupport.parkNanos(blocker,1);
   
// 阻塞當前線程直到deadline時間,相同的,也做了阻塞前記錄當前線程等待對象的操作
   
LockSupport.parkUntil(blocker,1);

   
// 喚醒處於阻塞狀態的線程Thread
   
LockSupport.unpark(new Thread());
}

 

Condition原理

在經典的生產者和消費者模式中,可以使用Object.wait()和Object. Notify()阻塞和喚醒線程,但這樣處理只有一個等待隊列。在可重入鎖ReentrantLock中,使用AQS的condition可以實現設置多個等待隊列,可以使用lock.newCondition生成一個等待隊列。

static void testCondition() throws InterruptedException {
   
// 需要結合lock使用
   
Lock lock = new ReentrantLock();
    final
Condition notEmpty = lock.newCondition();

   
// 將當前線程阻塞,調用await()之前必須先獲取鎖,
    // 調用await()時,將線程構造成節點加入等待隊列,同時釋放鎖,並掛起當前線程
   
notEmpty.await();
   
notEmpty.await(1, TimeUnit.MINUTES);
   
notEmpty.awaitNanos(1);
   
notEmpty.awaitUninterruptibly();
   
notEmpty.awaitUntil(new Date());

   
// 另一個線程將已經阻塞的線程喚醒
    // 其他線程調用signal()時也必須獲取鎖,
    // 當執行signal()方法時將等待隊列的節點移入到同步隊列,
    // 當線程退出臨界區釋放鎖時,喚醒同步隊列的首個節點
   
notEmpty.signal();
   
notEmpty.signalAll();
}

Fork/Join框架的理解

並行流:把一個內容分成多個數據塊,並用不同的線程分別處理每個數據塊的流。(fork/join框架)

串行流:則相反

Fork/Join框架:

在必要的情況下,將一個大的任務進行拆分(fork)成若干個子任務(拆到臨界值),再將一個個任務的結果進行join彙總。

Fork/Join與線程池的區別:

  Fork/Join採用“工作竊取模式”,當執行新的任務時可以將其拆分成更小的任務執行,並將小任務加到線程隊列中。然後再隨機從一個線程中偷一個任務並把他加入到自己的隊列中。

例如:CPU上有兩個線程A/B,A已經執行完了,B還有任務未執行。這時A將B隊尾的任務偷過來,加入到自己的隊列中。相對於傳統的線程池,Fork/Join更有效的使用了CPU資源。

// ForkJoin這個框架的實現需要繼承RecursiveTask 或者 RecursiveAction,
// RecursiveTask是有返回值的,相反RecursiveAction則沒有

@Data
public class TestForkJoinWork extends RecursiveTask<Long> {
   
private Long start;
    private
Long end;
    public static final
Long  CRITICAL = 10000L;

    public
TestForkJoinWork(Long start , Long end){
       
this.start = start;
        this
.end   = end;
   
}

   
@Override
   
protected Long compute() {
        Long length =
end - start;
        if
(length <= CRITICAL){
            Long sum =
0L;
            for
(Long i = start;i<=end;i++){
                sum += i
;
           
}
           
return sum;
       
}else{
            Long middle = (
start+end) / 2;
           
TestForkJoinWork right = new TestForkJoinWork(start,middle);
           
right.fork(); // 拆分 壓入線程隊列

           
TestForkJoinWork left = new TestForkJoinWork(middle+1,end);
           
left.fork(); // 拆分 壓入線程隊列

           
return right.join() + left.join();
       
}
    }
}


class TestForkJoinWorkDemo{

    
void test1(){
       
//Fork/Join實現
       
long l = System.currentTimeMillis();
       
ForkJoinPool forkJoinPool = new ForkJoinPool();//實現ForkJoin 就必須有ForkJoinPool的支持
       
TestForkJoinWork task = new TestForkJoinWork(0L,10000000000L);//參數爲起始值與結束值
       
Long invoke = forkJoinPool.invoke(task);
        long
l1 = System.currentTimeMillis();
       
System.out.println("invoke = " + invoke+"  time: " + (l1-l));
   
}

   
void test2(){
        
// 普通線程完成
       
Long x = 0L;
       
Long y = 10000000000L;
        long
l = System.currentTimeMillis();
        for
(Long i = 0L; i <= y; i++) {
            x += i
;
       
}
       
long l1 = System.currentTimeMillis();
       
System.out.println("invoke = " + x+"  time: " + (l1-l));
   
}

   
void test3(){
        
// 並行流
       
long l = System.currentTimeMillis();
       
//parallel()與sequential()在並行流與串行流中隨意切換
       
long reduce = LongStream.rangeClosed(0, 10000000000L).parallel().reduce(0, Long::sum);
        long
l1 = System.currentTimeMillis();
       
System.out.println("invoke = " + reduce+"  time: " + (l1-l));
   
}

   
public static void main(String[] args){
         TestForkJoinWorkDemo demo =
new TestForkJoinWorkDemo();
        
demo.test1();
        
demo.test2();
        
demo.test3();
       
/**
         * invoke = -5340232216128654848  time: 40213
         * invoke = -5340232216128654848  time: 52510
         * invoke = -5340232216128654848  time: 963
         */
   
}
}

 

分段鎖(JUC)的原理、鎖力度的減小思考

容器中有多把鎖,每一把鎖用於鎖容器中的一部分數據。當多線程時訪問容器中的不同數據段的數據時,線程間就不會發生鎖競爭了。因而有效的提高了高併發的訪問效率。例如ConcurrentHashMap使用的鎖分段技術,首先將數據分成一段一段的存儲,然後給每一段數據一把鎖,當一個線程佔用鎖訪問其中一個段數據時,其他段的數據也可被其他線程訪問。ConcurrentHashMap中使用了一個包含16個鎖的數組,每個鎖保護所在的散列桶的1/16,其中第N個散列桶由第(N mod 16)個鎖來保護。合理的使用散列算法來使關鍵字均勻分佈,那麼可使對鎖的請求減少到原來的1/16。這樣可使ConcurrentHashMap的並發達到16個線程。

獨佔鎖:只有一把鎖,每次只能一個線程能訪問。例如HashTable。採用串行方式,會降低其伸縮性。一般有三種方式降低鎖的競爭:

  1. 減少鎖的持有時間
  2. 降低鎖的請求頻率
  3. 使用帶有協調機制的獨佔鎖,這些機制允許更高的併發性。

八種阻塞隊列以及各個阻塞隊列的特性

public class TestQueue {
   
public static void main(String[] args) throws InterruptedException {
        Object obj =
new Object();
        boolean
flag;
       
Object val;
       
// 由數組結構組成的有界阻塞隊列
       
BlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(10);
       
// 隊未滿時,返回true,隊滿時則拋出異常IllegalStateException
       
flag = arrayBlockingQueue.add(obj);
       
// 隊未滿時,返回true,隊滿時返回false。非阻塞立即返回
       
arrayBlockingQueue.offer(obj);
       
// 隊未滿時直接插入無返回值,隊滿時阻塞等待,一直等到隊列未滿時再插入
       
arrayBlockingQueue.put(obj);

       
// 隊列不爲空時,返回隊首值並移除。隊爲空時拋出異常NoSuchElementException
       
val = arrayBlockingQueue.remove();
       
// 隊列不爲空時,返回隊首值並移除。隊爲空時返回null。非阻塞立即返回
       
val = arrayBlockingQueue.poll();
       
// 設定等待的時間,如果在指定時間內隊列爲空則返回null,不爲空則返回隊首值
       
val =  arrayBlockingQueue.poll(1,TimeUnit.MINUTES);
       
// 隊列不爲空返回隊首值並移除;當隊列爲空時會阻塞等待,一直等到隊列不爲空時再返回隊首值。
       
val = arrayBlockingQueue.take();

       
flag = arrayBlockingQueue.contains(obj);

       
// 由鏈表結構組成的有界阻塞隊列
       
BlockingQueue linkedBlockingQueue = new LinkedBlockingQueue(10);
       
// 支持優先級別排序的無界阻塞隊列 默認大小爲11
       
BlockingQueue priorityBlockingQueue = new PriorityBlockingQueue();
       
// 使用有限級隊列實現的無界阻塞隊列 PriorityQueue
       
BlockingQueue delayQueue = new DelayQueue();
       
// 不存儲元素的阻塞隊列
       
BlockingQueue synchronousQueue = new SynchronousQueue();
       
// 由鏈表結構組成的無界阻塞隊列
       
BlockingQueue linkedTransferQueue = new LinkedTransferQueue();
       
// 由鏈表結構組成的雙阻塞隊列
       
BlockingQueue linkedBlockingDeque = new LinkedBlockingDeque();
   
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章