简体   繁体   English

如何使CircularFifoQueue线程安全?

[英]How to make a CircularFifoQueue threadsafe?

I'd like to use a CircularFifoQueue with spring ExecutorService . 我想使用带有Spring ExecutorServiceCircularFifoQueue

The following does not compile, because CircularFifoQueue is not of type BlockingQueue . 以下内容无法编译,因为CircularFifoQueue的类型不是BlockingQueue But it shows what I'm trying to achieve: 但这显示了我正在努力实现的目标:

int threads = 10;
int queueSize = 500;
new java.util.concurrent.ThreadPoolExecutor(threads, threads, 0L, TimeUnit.MILLISECONDS, 
                new CircularFifoQueue(queueSize));

With: 附:

package org.apache.commons.collections4.queue;

public class CircularFifoQueue<E> extends AbstractCollection<E>
       implements Queue<E>, BoundedCollection<E>, Serializable

Question: does the code above provide thread safety (as CircularFifoQueue itself is not threadsafe)? 问题:上面的代码是否提供线程安全性(因为CircularFifoQueue本身不是线程安全的)? If not, how can I make it threadsafe? 如果没有,如何使它具有线程安全性?

Work queues are meant to be blocking, and hence you would need to add a decorator to make that CircularFifoQueue a BLockingQueue . 工作队列本来就是阻塞的,因此您需要添加一个decorator以使CircularFifoQueue成为BLockingQueue

class BlockingCircularFifoQueue<E> implements BlockingQueue<E>{
  private CircularFifoQueue<E> backingCollection;
  ...
} 

And delegate to the backing collection when needed. 并在需要时委托给后备集合。 You would need to get Conditions and Lock right of course. 当然,您将需要获得条件锁定权限。

You will have to practically write your own queue implementation. 实际上,您将必须编写自己的队列实现。 Since CircularFifoQueue uses an underlying array to hold the elements, I would take help of the ArrayBlockingQueue data structure in java.util.concurrent package as a starting point. 由于CircularFifoQueue使用底层数组来保存元素,因此我将以java.util.concurrent包中的ArrayBlockingQueue数据结构为帮助。

Example : 范例:

class ThreadSafeCircularFifoQueue<T> extends CircularFifoQueue<T> implements BlockingQueue<T> {

    /** Main lock guarding all access */
    final ReentrantLock lock;

    /** Condition for waiting takes */
    private final Condition notEmpty;

    /** Condition for waiting puts */
    private final Condition notFull;

    @Override
    public int size() {

        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return super.size();
        } finally {
            lock.unlock();
        }
    }

    //and so forth
}

You can synchronize using commons-collections QueueUtils.synchronizedQueue 您可以使用commons-collections QueueUtils.synchronizedQueue进行同步

Queue queue = QueueUtils.synchronizedQueue(new CircularFifoQueue());

But according to javadoc it needs additional synchronization for serial access: 但是根据javadoc,它需要额外的同步才能进行串行访问:

In order to guarantee serial access, it is critical that all access to the backing queue is accomplished through the returned queue. 为了保证串行访问,至关重要的是,对后备队列的所有访问都必须通过返回的队列来完成。

It is imperative that the user manually synchronize on the returned queue when iterating over it: 当用户遍历返回的队列时,必须手动对其进行同步:

 Queue queue = QueueUtils.synchronizedQueue(new CircularFifoQueue()); ... synchronized(queue) { Iterator i = queue.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); } } 

Failure to follow this advice may result in non-deterministic behavior. 不遵循此建议可能导致不确定的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM