【问题标题】:How to make a circular queue completely thread safe如何使循环队列完全线程安全
【发布时间】:2018-04-01 15:42:33
【问题描述】:

目前我刚刚向大多数方法添加了同步,因为如果没有它,这些方法就不是线程安全的。还有什么我需要实现的以确保它是线程安全的。

另外,有没有更好的方法来解决这个问题。目前只有一个线程可以同时使用循环队列,这似乎有点低效。

class CircularQueue<T> implements Iterable<T>{
  private T queue[];
  private int head, tail, size;
  @SuppressWarnings("unchecked")
  public CircularQueue(){
     queue = (T[])new Object[20];
     head = 0; tail = 0; size = 0;
  }
  @SuppressWarnings("unchecked")
  public CircularQueue(int n){ //assume n >=0
     queue = (T[])new Object[n];
     size = 0; head = 0; tail = 0;
  }
  public synchronized boolean join(T x){
    if(size < queue.length){
        queue[tail] = x;
        tail = (tail+1)%queue.length;
        size++;
        return true;
     }
     else return false; 
  }
  public synchronized T top(){
    if(size > 0)
        return queue[head];
    else
        return null;
  }
  public synchronized boolean leave(){
    if(size == 0) return false;
    else{
        head = (head+1)%queue.length;
        size--;
        return true;
    }
  }
  public synchronized boolean full(){return (size == queue.length);}
  public boolean empty(){return (size == 0);}

  public Iterator<T> iterator(){
      return new QIterator<T>(queue, head, size);
  }
  private static class QIterator<T> implements Iterator<T>{
      private T[] d; private int index; 
    private int size; private int returned = 0;
      QIterator(T[] dd, int head, int s){
          d = dd; index = head; size = s;
      }
    public synchronized boolean hasNext(){ return returned < size;}
    public synchronized T next(){
        if(returned == size) throw new NoSuchElementException();
        T item = (T)d[index];
        index = (index+1) % d.length;
        returned++;
        return item;
    }
    public void remove(){}
  }
}

如果您能提供任何建议或帮助,我们将不胜感激!

【问题讨论】:

  • 如果您想要充分利用多线程,您可以考虑使用lock free

标签: java concurrency thread-safety synchronized java-threads


【解决方案1】:

除了缺少使您的empty() 方法同步之外,您的迭代器与主机队列的隔离不够充分。问题不在于它的方法在迭代器实例上是同步的,尽管它们确实如此。您的迭代器正在复制主机队列的数据,以便遍历队列的快照。这是个好主意,在这种情况下,在迭代器本身上进行同步是正确的做法。

但是你没有完全实现它。具体来说,构造函数执行d = dd; 是不够的。数组是对象,因此只需将迭代器的数组引用设置为引用主机队列使用的相同数组对象。相反,您需要制作该数组的副本。有几种方法可以做到这一点,但我更喜欢调用数组的 clone() 方法——简短而甜蜜。

即便如此,仅靠类的方法同步也无法解决线程安全问题。其中一些涉及对象在多个方法调用上的一致性。例如,假设一个线程将一个对象加入队列实例中。如果该队列在线程之间共享,则使对象入队的队列不能安全地假设它可以稍后将对象出队,或者如果确实使一个对象出队,则它将与入队的对象相同。如果它希望能够做出这样的假设,那么它必须要么提供更广泛的保护,要么确保它使用的队列实例不被共享。

如果它们确实是可变的,其他问题则围绕着入队对象的突变。它们的状态不受队列及其迭代器同步的保护。

【讨论】:

  • 非常感谢您的详细回答,您给了我很多思考
【解决方案2】:

empty() 不同步,迭代器方法上的同步保护迭代器(这可能没用),但不保护队列本身。

【讨论】:

  • 为了保护队列免受迭代器的影响,克隆队列然后基于不可变克隆创建迭代器是否可以接受?
  • @user3704648 当然,它可以解决问题;不过这可能有点矫枉过正。
  • 你会建议什么?
  • @user3704648 实际上,这可能是最好的解决方案
猜你喜欢
  • 2013-03-22
  • 1970-01-01
  • 2018-08-15
  • 1970-01-01
  • 2014-12-14
  • 2012-05-30
  • 2012-11-05
  • 2012-07-06
  • 1970-01-01
相关资源
最近更新 更多