TransferQueue

摘录

Java 7中的TransferQueue
原文链接,译文链接,作者:Alex Miller,译者:Greenster,校对:梁海舰
Java7中加入了JSR 166y规范对集合类和并发类库的改进。其中的一项是增加了接口TransferQueue和其实现类LinkedTransferQueue。

TransferQueue继承了BlockingQueue(BlockingQueue又继承了Queue)并扩展了一些新方法。BlockingQueue(和Queue)是Java 5中加入的接口,它是指这样的一个队列:当生产者向队列添加元素但队列已满时,生产者会被阻塞;当消费者从队列移除元素但队列为空时,消费者会被阻塞。

TransferQueue则更进一步,生产者会一直阻塞直到所添加到队列的元素被某一个消费者所消费(不仅仅是添加到队列里就完事)。新添加的transfer方法用来实现这种约束。顾名思义,阻塞就是发生在元素从一个线程transfer到另一个线程的过程中,它有效地实现了元素在线程之间的传递(以建立Java内存模型中的happens-before关系的方式)。

TransferQueue还包括了其他的一些方法:两个tryTransfer方法,一个是非阻塞的,另一个带有timeout参数设置超时时间的。还有两个辅助方法hasWaitingConsumer()和getWaitingConsumerCount()。

当我第一次看到TransferQueue时,首先想到了已有的实现类SynchronousQueue。SynchronousQueue的队列长度为0,最初我认为这好像没多大用处,但后来我发现它是整个Java Collection Framework中最有用的队列实现类之一,特别是对于两个线程之间传递元素这种用例。

TransferQueue相比SynchronousQueue用处更广、更好用,因为你可以决定是使用BlockingQueue的方法(译者注:例如put方法)还是确保一次传递完成(译者注:即transfer方法)。在队列中已有元素的情况下,调用transfer方法,可以确保队列中被传递元素之前的所有元素都能被处理。Doug Lea说从功能角度来讲,LinkedTransferQueue实际上是ConcurrentLinkedQueue、SynchronousQueue(公平模式)和LinkedBlockingQueue的超集。而且LinkedTransferQueue更好用,因为它不仅仅综合了这几个类的功能,同时也提供了更高效的实现。

Joe Bowbeer提供了一篇William Scherer, Doug Lea, and Michael Scott的论文,在这篇论文中展示了LinkedTransferQueue的算法,性能测试的结果表明它优于Java 5的那些类(译者注:ConcurrentLinkedQueue、SynchronousQueue和LinkedBlockingQueue)。LinkedTransferQueue的性能分别是SynchronousQueue的3倍(非公平模式)和14倍(公平模式)。因为像ThreadPoolExecutor这样的类在任务传递时都是使用SynchronousQueue,所以使用LinkedTransferQueue来代替SynchronousQueue也会使得ThreadPoolExecutor得到相应的性能提升。考虑到executor在并发编程中的重要性,你就会理解添加这个实现类的重要性了。

Java 5中的SynchronousQueue使用两个队列(一个用于正在等待的生产者、另一个用于正在等待的消费者)和一个用来保护两个队列的锁。而LinkedTransferQueue使用CAS操作(译者注:参考wiki)实现一个非阻塞的方法,这是避免序列化处理任务的关键。这篇论文还罗列了很多的细节和数据,如果你感兴趣,非常值得一读。

带优先级的TransferQueue

package mytest;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TransferQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

public class MyTransferQueue<E> extends PriorityBlockingQueue<E> implements TransferQueue<E> {
    private AtomicInteger counter;
    private LinkedBlockingQueue<E> transfered;
    private ReentrantLock lock;

    public MyTransferQueue() {
        counter = new AtomicInteger(0);
        lock = new ReentrantLock();
        transfered = new LinkedBlockingQueue<>();
    }

    /**
     * 若当前存在一个正在等待获取的消费者线程(使用take()或者poll()函数),使用该方法会即刻转移/传输对象元素e;<br>
     * 若不存在,则返回false,并且不进入队列。这是一个不阻塞的操作。
     */
    @Override
    public boolean tryTransfer(E e) {
        lock.lock();
        boolean value;
        if (counter.get() == 0) {
            value = false;
        } else {
            put(e);// 从不会阻塞
            value = true;
        }
        lock.unlock();
        return value;
    }

    /**
     * 若当前存在一个正在等待获取的消费者线程,即立刻移交之;否则,会插入当前元素e到队列尾部,并且等待进入阻塞状态,到有消费者线程取走该元素。
     */
    @Override
    public void transfer(E e) throws InterruptedException {
        lock.lock();
        if (counter.get() != 0) {
            put(e);// 立即将元素发送到一个正在等待的消费者
            lock.unlock();
        } else {
            transfered.add(e);// 如果没有等待中的消费者,则将元素存储到transferd队列并等待试图获得元素的第一个消费者
            lock.unlock();
            synchronized (e) {
                e.wait();
            }
        }

    }

    // 若当前存在一个正在等待获取的消费者线程,会立即传输给它;否则将插入元素e到队列尾部,并且等待被消费者线程获取消费掉;
    // 若在指定的时间内元素e无法被消费者线程获取,则返回false,同时该元素被移除。
    @Override
    public boolean tryTransfer(E e, long timeout, TimeUnit unit) throws InterruptedException {
        lock.lock();
        if (counter.get() != 0) {
            put(e);// 立即将元素发送到一个正在等待的消费者
            lock.unlock();
            return true;
        } else {
            transfered.add(e);// 如果没有等待中的消费者,则将元素存储到transferd队列并等待试图获得元素的第一个消费者
            lock.unlock();
            e.wait(TimeUnit.MILLISECONDS.convert(timeout, unit));
            lock.lock();
            if (transfered.contains(e)) {
                transfered.remove(e);// 移除未被取走的元素
                lock.unlock();
                return false;
            } else {
                lock.unlock();
                return true;
            }
        }
    }

    // 判断是否存在消费者线程。
    @Override
    public boolean hasWaitingConsumer() {
        return (counter.get() != 0);
    }

    // 获取所有等待获取元素的消费线程数量。
    @Override
    public int getWaitingConsumerCount() {
        return counter.get();
    }

    @Override
    public E take() throws InterruptedException {
        lock.lock();
        counter.incrementAndGet();
        E value = transfered.poll();
        if (value == null) {
            lock.unlock();
            value = super.take();// 取得元素再次获得锁
            lock.lock();// ??
        } else {
            synchronized (value) {
                value.notify();
            }
        }
        counter.decrementAndGet();
        lock.unlock();
        return value;
    }

    static class Event implements Comparable<Event> {
        private String thread;
        private int priority;

        public Event(String thread, int priority) {
            this.thread = thread;
            this.priority = priority;
        }

        public String getThread() {
            return thread;
        }

        public int getPriority() {
            return priority;
        }

        @Override
        public int compareTo(Event o) {
            if (this.priority > o.getPriority()) {
                return -1;
            } else if (this.priority < o.getPriority()) {
                return 1;
            }
            return 0;
        }

    }

    static class Producer implements Runnable {
        private MyTransferQueue<Event> buffer;

        public Producer(MyTransferQueue<Event> buffer) {
            this.buffer = buffer;
        }

        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                Event e = new Event(Thread.currentThread().getName(), i);
                buffer.put(e);
            }
        }
    }

    static class Consumer implements Runnable {
        private MyTransferQueue<Event> buffer;

        public Consumer(MyTransferQueue<Event> buffer) {
            this.buffer = buffer;
        }

        @Override
        public void run() {
            for (int i = 0; i < 1002; i++) {
                try {
                    Event take = buffer.take();
                    System.out.println("Thread name:" + take.getThread() + ";priority:" + take.getPriority());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyTransferQueue<Event> buffer = new MyTransferQueue<Event>();
        Producer producer = new Producer(buffer);
        Thread producerThread[] = new Thread[10];
        for (int i = 0; i < producerThread.length; i++) {
            producerThread[i] = new Thread(producer);
            producerThread[i].start();
        }
        Consumer consumer = new Consumer(buffer);
        Thread consumerThread = new Thread(consumer);
        consumerThread.start();
        System.out.println("Main :Buffer:Consumer count:" + buffer.getWaitingConsumerCount());
        Event myEvent = new Event("Core event", 0);
        buffer.transfer(myEvent);
        System.out.println("Main my event has been transfered");

        for (int i = 0; i < producerThread.length; i++) {
            producerThread[i].join();
        }
        TimeUnit.SECONDS.sleep(1);

        System.out.println("Main :Buffer:Consumer count:" + buffer.getWaitingConsumerCount());

        myEvent = new Event("Core event 2", 0);
        buffer.transfer(myEvent);

        consumerThread.join();

        System.out.println("Main End of the program");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值