JAVA多线程-常用JUC工具类及阻塞队列

工具类

CountDownLactch

简述
  • 允许一个或多个线程等待,直到在其他线程中执行的一组操作完成,同步辅助。
  • CountDownLatch 类用给定的计数初始化。
  • await 方法阻塞,直到由于 countDown() 方法的调用而导致当前计数达到零后所有等待线程被释放,并且任何后续的 await 调用立即返回。
  • 这是一个一次性的计数操作,因为计数无法重置。
  • 如果需要重置计数的版本,请考虑使用 **CyclicBarrier **类。
构造函数
/*
    参数 
    count 减的次数 countDown() 必须调用之前线程可以通过 await() 
    异常 
    IllegalArgumentException  如果此时 count 为负数。
*/
public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}
await方法
/*
    导致当前线程等到锁存器计数到零,除非线程是interrupted 。 
    如果当前计数为零,则此方法立即返回。 

    如果当前计数大于零,则当前线程将被禁用以进行线程调度,并处于休眠状态,直至发生两件事情之一: 

    由于countDown()方法的调用,计数达到零; 要么 
    一些其他线程interrupts当前线程。 
    如果当前线程: 

    在进入该方法时设置了中断状态; 要么 
    是interrupted等待, 
    然后InterruptedException被关上,当前线程的中断状态被清除。 
*/
public void await() throws InterruptedException {
    // 获取可中断的共享
    sync.acquireSharedInterruptibly(1); 
}
public final void acquireSharedInterruptibly(int arg)
    throws InterruptedException {
    // 如果当前await的线程被中断了,那就抛出异常
    if (Thread.interrupted())
        throw new InterruptedException();
    // 尝试获取共享
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}
private void doAcquireSharedInterruptibly(int arg)
    throws InterruptedException {
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            if (p == head) {
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
案例
package JUC.api;

import JUC.myenum.CountryEnum;

import java.util.concurrent.CountDownLatch;

/**
 * @author zhaolimin
 * @date 2021/11/15
 * @apiNote CountDownLatch倒计时的使用
 */
public class CountDownLatchDemo {

    private int count = 6;

    public int getCount() {
        return this.count;
    }

    public static void main(String[] args) throws Exception{

        fight();

    }

    public static void fight() throws Exception{
        CountDownLatch countDownLatch = new CountDownLatch(new CountDownLatchDemo().getCount());

        for (int i = 1; i < 7; i++) {

            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "\t被秦所灭。。。");
                countDownLatch.countDown();
            }, CountryEnum.foreachCountryEnum(i).getResultMessage()).start();
        }

        countDownLatch.await();
        System.out.println("秦朝建立");
    }
}

package JUC.myenum;

/**
 * @author zhaolimin
 * @date 2021/11/15
 * @apiNote 国家枚举
 */
public enum CountryEnum {

    ONE(1,"齐"),
    TWO(2,"楚"),
    THREE(3,"燕"),
    FOUR(4,"韩"),
    FIVE(5,"赵"),
    SIX(6,"魏");

    private Integer resultCode;
    private String resultMessage;

    CountryEnum(Integer resultCode, String resultMessage) {
        this.resultCode = resultCode;
        this.resultMessage = resultMessage;
    }

    public Integer getResultCode() {
        return resultCode;
    }

    public String getResultMessage() {
        return resultMessage;
    }

    // 找到对应的枚举
    public static CountryEnum foreachCountryEnum(int index) {

        // 枚举天生就带着自己的一种遍历方法
        CountryEnum[] values = CountryEnum.values();
        for (CountryEnum value:
             values) {
            // 找到对应枚举就返回
            if (index == value.getResultCode()) {
                return value;
            }
        }
        // 找不到对应枚举就返回null
        return null;
    }
}
/*
    齐	被秦所灭。。。
    赵	被秦所灭。。。
    魏	被秦所灭。。。
    韩	被秦所灭。。。
    楚	被秦所灭。。。
    燕	被秦所灭。。。
    秦朝建立
*/

CyclicBarrier

简述
  • 允许一组线程全部等待彼此达到共同屏障点的同步辅助。
  • 循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此
  • 屏障被称为循环 ,因为它可以在等待的线程被释放之后重新使用
  • 它会在某个代码段后设置 await 方法,只有执行到当前 await 方法的代码段的线程达到一定数量才会解除阻塞状态运行别的。
构造函数
  • 创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待时,它将跳闸,当屏障跳闸时执行给定的屏障动作,由最后一个进入屏障的线程执行。
public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    this.barrierCommand = barrierAction; // 到达计数点之后要执行的动作,Runnable接口
}
await方法
    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }
private int dowait(boolean timed, long nanos)
    throws InterruptedException, BrokenBarrierException,
TimeoutException {
    // 可以看到这个还是一个可重入锁
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        final Generation g = generation;

        // 判断屏障是否被破坏
        if (g.broken)
            throw new BrokenBarrierException();
	    // 判断当前被阻塞线程是否被中断
        if (Thread.interrupted()) {
            // 中断就打破屏障
            breakBarrier();
            throw new InterruptedException();
        }

        // 通过减法来进行判断
        int index = --count;
        // 如果此时循环等待的await的线程数够了,就放行 runnable 线程的动作
        if (index == 0) {  // tripped
            boolean ranAction = false;
            try {
                final Runnable command = barrierCommand;
                 // 如果构造函数里传入了屏障结束之后要进行的动作
                if (command != null)
                    // 如果有的话就运行
                    command.run();
                ranAction = true;
                nextGeneration();
                return 0;
            } finally {
                if (!ranAction)
                    breakBarrier();
            }
        }

        // loop until tripped, broken, interrupted, or timed out
        for (;;) {
            try {
                if (!timed)
                    trip.await();
                else if (nanos > 0L)
                    nanos = trip.awaitNanos(nanos);
            } catch (InterruptedException ie) {
                if (g == generation && ! g.broken) {
                    breakBarrier();
                    throw ie;
                } else {
                    // We're about to finish waiting even if we had not
                    // been interrupted, so this interrupt is deemed to
                    // "belong" to subsequent execution.
                    Thread.currentThread().interrupt();
                }
            }

            if (g.broken)
                throw new BrokenBarrierException();

            if (g != generation)
                return index;

            if (timed && nanos <= 0L) {
                breakBarrier();
                throw new TimeoutException();
            }
        }
    } finally {
        lock.unlock();
    }
}
案例
package JUC.api;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * @author zhaolimin
 * @date 2021/11/15
 * @apiNote  CyclicBarrier循环屏障使用
 */
public class CyclicBarrierDemo {

    public static void main(String[] args) {

        // 它会等待到七个线程运行结束之后最后再运行 Runnable 接口实现的方法。
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            System.out.println("召唤神龙!");
        });

        for (int i = 1; i < 8; i++) {
            int temp = i;
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "\t 收集到第 " + temp + "颗龙珠");

                // 收集完一个龙珠就在这阻塞等待
                // 等待七个龙珠也就是七个线程都运行到这里,才执行解锁。
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }

    }
}
/*
    1	 收集到第 1颗龙珠
    7	 收集到第 7颗龙珠
    6	 收集到第 6颗龙珠
    5	 收集到第 5颗龙珠
    2	 收集到第 2颗龙珠
    4	 收集到第 4颗龙珠
    3	 收集到第 3颗龙珠
    召唤神龙!
*/

Semaphore

简述
  • 一个计数信号量。
  • 在概念上,信号量维持一组许可证。 如果有必要,每个acquire()阻塞直到许可证可用,然后才能使用它。
  • 每个release()添加许可证潜在地释放阻塞获取方
  • 但是,没有使用实际的许可证对象 Semaphore 只保留可用数量的计数,并相应地执行就可以。
  • 一般用在多个线程抢多个资源的情况。
  • 可以变相替代 synchronizedlock
构造函数
// 不设置第二个参数默认非公平锁
// 第一个是信号量数
public Semaphore(int permits, boolean fair) {
    sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
acquire方法
// 从该信号量获取许可证,阻止直到可用,或线程为 interrupted
public void acquire() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
    throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}
private void doAcquireSharedInterruptibly(int arg)
    throws InterruptedException {
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    /*
        如果没有足够的许可证可用,那么当前线程将被禁用以进行线程调度,并且处于休眠状态,直到发生两件事情之一: 

        一些其他线程调用此信号量的一个release方法,当前线程旁边将分配许可证,并且可用许可证的数量满足此请求;
        要么一些其他线程interrupts当前线程。
    */
    try {
        for (;;) {
            final Node p = node.predecessor();
            if (p == head) {
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
案例
  • 信号量控制的代码段为:
    • semaphore.acquire() 与 semaphore.release() 中间的那一段代码段。
package JUC.api;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * @author zhaolimin
 * @date 2021/11/15
 * @apiNote 信号量测试
 */
public class SemaphoreDemo {

    public static void main(String[] args) {

        // 不设置第二个参数默认非公平锁
        // 模拟十个车位。
        Semaphore semaphore = new Semaphore(5, false);

        // 模拟二十辆车来
        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "车\t抢到车位。。。");
                    TimeUnit.SECONDS.sleep(3); // 暂停一会线程,假装每个车在车位上停三秒
                    System.out.println(Thread.currentThread().getName() + "车\t停车三秒后离开车位!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release();
                }
            }, String.valueOf(i)).start();
        }
    }
}
/*
    1车	抢到车位。。。
    5车	抢到车位。。。
    4车	抢到车位。。。
    2车	抢到车位。。。
    3车	抢到车位。。。
    5车	停车三秒后离开车位!
    3车	停车三秒后离开车位!
    2车	停车三秒后离开车位!
    6车	抢到车位。。。
    4车	停车三秒后离开车位!
    8车	抢到车位。。。
    9车	抢到车位。。。
    7车	抢到车位。。。
    1车	停车三秒后离开车位!
    10车	抢到车位。。。
    6车	停车三秒后离开车位!
    9车	停车三秒后离开车位!
    8车	停车三秒后离开车位!
    10车	停车三秒后离开车位!
    7车	停车三秒后离开车位!
*/

阻塞队列

什么是阻塞队列

  • 顾名思义是一个队列。
  • 当阻塞队列是空的时候线程从队列中获取元素的操作将会被阻塞。
  • 当阻塞队列是满的时候线程往队列里添加元素的操作将会被阻塞。
  • 很像生产者消费者模型。

| 在这里插入图片描述

线程一往阻塞队列中添加元素,线程二往阻塞队列中移除元素
  • 阻塞队列有没有好的一面
    • JUC 发布之前,多线程环境下,我们每个开发者都得自己去控制什么时候阻塞线程什么时候唤醒线程,尤其是要兼顾效率和线程安全,这样做会给程序带来很大的复杂度,容易出错,不好测试。
    • 我们不用关心什么时候需要阻塞线程,什么时候需要唤醒线程,因为这一切都被阻塞队列包了。
    • 在多线程领域:
      • 所谓阻塞,就是某些情况下会挂起线程,一旦条件满足,被挂起的线程又会被自动唤醒。
  • 不得不阻塞的话如何管理?

ArrayBlockingQueue

简述
  • 它是一个基于数组结构的有界限的阻塞队列。
  • 此队列按照 **FIFO(先进先出)**原则对元素进行排序。

LinkedBlockingQueue

简述
  • 一个基于链表结构的阻塞队列,此队列按照 **FIFO(先进先出)**排序元素。
  • 有界的,默认大小为 int 类型的最大值。
  • 吞吐量通常要高于 ArrayBlockingQueue

SynchronousQueue

简述
  • 一个不存储元素的阻塞队列。
  • 每个插入操作必须等待另一个线程调用移除操作
  • 每个 put() 对应一个 take()
  • 否则插入操作一直处于阻塞状态,吞吐量通常高于 LinkedBlockingQueue
  • 慎用。
示例
package JUC.block;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

/**
 * @author zhaolimin
 * @date 2021/11/16
 * @apiNote
 */
public class SynchronousQueueDemo {

    public static void main(String[] args) {

        BlockingQueue<String> strings = new SynchronousQueue<>();

            new Thread(() -> {
                try {
                    // 不断尝试往里添加
                    System.out.println(Thread.currentThread().getName() + "线程\t 添加 1 ");
                    strings.put("1");
                    System.out.println(Thread.currentThread().getName() + "线程\t 添加 2 ");
                    strings.put("2");
                    System.out.println(Thread.currentThread().getName() + "线程\t 添加 3 ");
                    strings.put("3");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "A").start();

            new Thread(() -> {
                try {
                    // 过五秒钟取一次,造成上面添加的阻塞
                    TimeUnit.SECONDS.sleep(5);
                    System.out.println(Thread.currentThread().getName() + "线程\t 取出 1 ");
                    strings.take();
                    TimeUnit.SECONDS.sleep(5);
                    System.out.println(Thread.currentThread().getName() + "线程\t 取出 2 ");
                    strings.take();
                    TimeUnit.SECONDS.sleep(5);
                    System.out.println(Thread.currentThread().getName() + "线程\t 取出 3 ");
                    strings.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "B").start();
    }
}
/*
    A线程	 添加 1 
    B线程	 取出 1 
    A线程	 添加 2 
    B线程	 取出 2 
    A线程	 添加 3 
    B线程	 取出 3 
*/

其它阻塞队列

PriorityBlockingQueue
  • 支持优先级排序的无界阻塞队列
DelayQueue
  • 使用优先级队列实现的延迟无界阻塞队列
LinkedTransferQueue
  • 由链表构成的无界阻塞队列
LinkedBlockingDeque
  • 由链表构成的双向阻塞队列

BlockingQueue的核心方法

方法类型抛出异常特殊值阻塞超时
插入add(e)offer(e)put(e)offer(e,time,unit)
移除remove()poll()take()poll(time,unit)
检查element()peek()不可用不可用
抛出异常当阻塞队列满了的时候,再往队列里 add数据 会抛出IllegalStateException:Queue full异常,当阻塞队列空的时候,再往队列里 remove 数据会抛出NoSuchElementException异常。
特殊值插入方法,成功返回true失败返回false;移除方法,成功返回出队元素队列里面没有就返回null
一直阻塞当阻塞队列满的时候,生产者线程继续往队列里 put 元素的话,队列会一直阻塞生产线程直到 put 数据或者响应中断退出。当阻塞队列空的时候,消费者线程试图从队列里 take 元素的话,队列会一直阻塞消费者线程直到队列可用。
超时过时不候

抛出异常组测试

  • 测试了 BlockingQueue会抛出异常的三个方法的使用。
package JUC.api;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * @author zhaolimin
 * @date 2021/11/15
 * @apiNote 阻塞队列demo
 */
public class BlockingQueueDemo {

    public static void main(String[] args) throws Exception {

        System.out.println("--------------------初始容量为三插入三个数据-----------------------");
        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3); // 没有无参构造,队列初始化容量为三
        System.out.println(blockingQueue.add("a"));
        System.out.println(blockingQueue.add("b"));
        System.out.println(blockingQueue.add("c"));
        System.out.println("----------------------容量刚好到三---------------------");
        System.out.println();
        // 初始容量为三,三过了之后就会抛异常 Queue full
        try {
            System.out.println("----------------------添加第四个数据越界抛出异常---------------------");
            System.out.println(blockingQueue.add("d"));
            System.out.println();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }

        System.out.println("检查一下当前元素空不空,不空的话队首元素是:" + blockingQueue.element());
        System.out.println();

        System.out.println("--------------------移除三个数据-----------------------");
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println(blockingQueue.remove());
        System.out.println();
        try {
            System.out.println("--------------------移除第四个数据发现抛出异常-----------------------");
            // 队列中没有元素了再移除会抛异常 NoSuchElementException
            System.out.println(blockingQueue.remove());
            System.out.println();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
    }
}

/*	
    --------------------初始容量为三插入三个数据-----------------------
    true
    true
    true
    ----------------------容量刚好到三---------------------

    ----------------------添加第四个数据越界抛出异常---------------------
    检查一下当前元素空不空,不空的话队首元素是:a

    --------------------移除三个数据-----------------------
    a
    b
    c

    --------------------移除第四个数据发现抛出异常-----------------------
    java.lang.IllegalStateException: Queue full
        at java.util.AbstractQueue.add(AbstractQueue.java:98)
        at java.util.concurrent.ArrayBlockingQueue.add(ArrayBlockingQueue.java:312)
        at JUC.api.BlockingQueueDemo.main(BlockingQueueDemo.java:25)
    Exception in thread "main" java.util.NoSuchElementException
        at java.util.AbstractQueue.remove(AbstractQueue.java:117)
        at JUC.api.BlockingQueueDemo.main(BlockingQueueDemo.java:42)
*/

返回布尔值组(特殊值组)测试

  • 测试了 BlockingQueue 中会返回特殊值的三个方法的使用。
package JUC.block;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * @author zhaolimin
 * @date 2021/11/15
 * @apiNote 阻塞队列demo
 */
public class BlockingQueueDemo {

    public static void main(String[] args) throws Exception {
        System.out.println("--------------------初始容量为三插入三个数据-----------------------");
        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3); // 没有无参构造,队列初始化容量为三
        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
        System.out.println("----------------------容量刚好到三---------------------");
        
        System.out.println("尝试插入第四个值,返回插入结果:" + blockingQueue.offer("d")); // 我们看到boolean值组就是不抛异常
        System.out.println("检查一下当前元素空不空,不空的话队首元素是:" + blockingQueue.peek());
        System.out.println();
        
        System.out.println("----------------------取元素---------------------");
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll()); // 队列没有值了就返回null
    }
}

/*
    --------------------初始容量为三插入三个数据-----------------------
    true
    true
    true
    ----------------------容量刚好到三---------------------
    尝试插入第四个值,返回插入结果:false
    检查一下当前元素空不空,不空的话队首元素是:a

    ----------------------取元素---------------------
    a
    b
    c
    null
*/

阻塞组测试

  • 测试了 BlockingQueue 中会阻塞值的两个方法的使用。
  • 由于这个方法在多线程下可能更直观,于是就换成了多线程的写法。
package JUC.block;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * @author zhaolimin
 * @date 2021/11/15
 * @apiNote 阻塞队列demo
 */
public class BlockingQueueDemo {

    public static void main(String[] args) throws Exception {
        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3); // 没有无参构造,队列初始化容量为三
        for (int i = 1; i <= 5; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + "\t 尝试放入数据。。。");
                    blockingQueue.put("a");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t 放入数据成功!");
            }, String.valueOf(i)).start();
        }

        for (int i = 1; i <= 5; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + "\t 尝试取出数据。。。");
                    blockingQueue.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t 取出数据成功!");
            }, String.valueOf(i)).start();
        }
    }
}
/*
    1	 尝试放入数据。。。
    5	 尝试放入数据。。。
    4	 尝试放入数据。。。
    3	 尝试放入数据。。。
    2	 尝试放入数据。。。
    4	 放入数据成功!
    5	 放入数据成功!
    1	 放入数据成功!
    1	 尝试取出数据。。。
    3	 尝试取出数据。。。
    2	 尝试取出数据。。。
    3	 放入数据成功!
    1	 取出数据成功!
    3	 取出数据成功!
    5	 尝试取出数据。。。
    2	 放入数据成功!
    4	 尝试取出数据。。。
    4	 取出数据成功!
    2	 取出数据成功!
    5	 取出数据成功!
*/
  • 放入成功的提示语句不可能有三个以上同时打印出来
  • 取出成功的提示语句同样也不可能有三个以上同时又打印出来
  • 每个线程都打印了四条不同的提示语句,与预期线程安全期望结果一致。

超时组测试

  • 每个线程都打印了两条不同的提示语句,与预期线程安全期望结果一致。
package JUC.block;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @author zhaolimin
 * @date 2021/11/15
 * @apiNote 阻塞队列demo
 */
public class BlockingQueueDemo {

    public static void main(String[] args) throws Exception {
        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3); // 没有无参构造,队列初始化容量为三
        for (int i = 1; i <= 5; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + "\t 放入数据成功!" 
                                       + blockingQueue.offer("a", 5, TimeUnit.MICROSECONDS));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }

        for (int i = 1; i <= 5; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + "\t 取出数据成功!" 
                                       + blockingQueue.poll(10, TimeUnit.MICROSECONDS));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
    }
}
/*
    1	 放入数据成功!true
    2	 取出数据成功!a
    2	 放入数据成功!true
    5	 放入数据成功!true
    3	 放入数据成功!true
    5	 取出数据成功!null  // 走到这一步我们可以看到这个线程等不了了,直接超时走人了,没取到数据。
    4	 取出数据成功!a
    3	 取出数据成功!a
    1	 取出数据成功!a
    4	 放入数据成功!true
*/

码云仓库同步笔记,可自取欢迎各位star指正:https://gitee.com/noblegasesgoo/notes

如果出错希望评论区大佬互相讨论指正,维护社区健康大家一起出一份力,不能有容忍错误知识。
										—————————————————————— 爱你们的 noblegasesgoo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值