SynchronousQueue简介

概述

SynchronousQueue是一个特别的队列,在它的内部没有容器。其中每个插入操作必须等待另一个线程相应的删除操作,反之亦然。一个添加线程当它调用添加(put())方法时,如果没有其他线程尝试删除元素,此插入线程必须阻塞,等待删除线程调用删除操作,删除操作将会唤醒插入线程,同时删除线程会获取插入线程的数据。

验证代码如下:

public class SynchronousQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        final SynchronousQueue<Integer> queue = new SynchronousQueue<>();
        Thread putThread = new Thread(() -> {
            System.out.println("put thread start");
            try {
                queue.put(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("put thread end");
        });

        Thread takeThread = new Thread(() -> {
            System.out.println("take thread start");
            try {
                System.out.println("take from : " + queue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("take from : " + poll);
            System.out.println("take thread end");
        });

        putThread.start();
        Thread.sleep(3000);
        takeThread.start();
    }
}

打印结果如下:

在这里插入图片描述

从结果中可以看出,put线程执行queue.put(1)后线程阻塞,直到take线程执行queue.take()后被唤醒。

put(E e):向队列提交一个元素,阻塞直到其他线程take()或poll()。

boolean offer(E e):向队列提交一个元素,如果此时有其他线程正在被take()阻塞(即其他线程已准备接收数据)或者碰巧有poll()操作,那么返回true,否则返回false。

E take():已有put()阻塞线程时,删除并返回put线程的元素;否则阻塞当前线程直至有其他线程put()或offer()时,删除并返回添加的元素。

E poll():如果此时已有线程被put()阻塞或者碰巧有offer()操作,则返回并删除该元素;否则返回null。

boolean add():其内部调用offer()方法,只是当offer()返回值为false时抛出IllegalStateException异常。

E remove():内部调用poll()方法,只是当poll()返回值为null时抛出NoSuchElementException异常。

SynchronousQueue调用peek()方法永远返回null,源码如下(jdk1.8):

public E peek() {        
    return null;
}

而调用element()方法时永远抛出NoSuchElementException,SynchronousQueue中的element()方法继承于AbstractQueue抽象类,且未重写,其源码如下(jdk1.8):

public E element() {
    E x = peek();
    if (x != null)
        return x;
    else
        throw new NoSuchElementException();
}

实现原理

SynchronousQueue实现策略通常分为公平模式和非公平模式,公平模式底层实现使用TransferQueue内部队列,非公平模式底层实现使用TransferStack内部栈。源码如下:

// 添加方法
public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    if (transferer.transfer(e, false, 0) == null) {
        Thread.interrupted();
        throw new InterruptedException();
    }
}

public boolean offer(E e, long timeout, TimeUnit unit)
    throws InterruptedException {
    if (e == null) throw new NullPointerException();
    if (transferer.transfer(e, true, unit.toNanos(timeout)) != null)
        return true;
    if (!Thread.interrupted())
        return false;
    throw new InterruptedException();
}

public boolean offer(E e) {
    if (e == null) throw new NullPointerException();
    return transferer.transfer(e, true, 0) != null;
}

// 删除方法
public E take() throws InterruptedException {
    E e = transferer.transfer(null, false, 0);
    if (e != null)
        return e;
    Thread.interrupted();
    throw new InterruptedException();
}

public E poll(long timeout, TimeUnit unit) throws InterruptedException {
    E e = transferer.transfer(null, true, unit.toNanos(timeout));
    if (e != null || !Thread.interrupted())
        return e;
    throw new InterruptedException();
}

public E poll() {
    return transferer.transfer(null, true, 0);
}

从以上代码可以看出无论时添加还是删除元素都是调用transferer对象的transfer()方法。

private transient volatile Transferer<E> transferer;

public SynchronousQueue() {
    this(false);
}

public SynchronousQueue(boolean fair) {
    transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}

从其构造函数可以证明上面的结论,且默认为非公平模式。公平模式下先进先出,非公平模式下先进后出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值