我目前正在尝试实现受线程保护的链表。可实现的方法之一是take(),它删除最近添加的元素,如果列表为空,则等待添加元素。我对Java线程和同步的了解还很差,所以我想知道这种实现是否可行。特别是,我想知道如果在put()之前调用take()会发生什么情况。由于它们都使用相同的锁定对象,因此我感觉好像在put()之前调用了take()一样,take()的锁定从未释放,因此put()会被卡住,以尝试获取该lock()。这是我的实现

//Globals
private final Lock lock = new ReentrantLock();
final Condition notEmpty = lock.newCondition();

 public boolean put(int address) {
    Node newnode = new Node(null, null, address);
    lock.lock();
    if(first == null) {
        try {
            first = newnode;
            last = newnode;
            size++;
            notEmpty.signal();
        }
        finally {
            lock.unlock();
        }
    }
    else {
        if(contains(address) == true) {
            remove(address);
        }

        first.prev = newnode;
        newnode.next = first;
        first = newnode;
        size++;
    }

    return true;
}


为了

    public int take() throws InterruptedException {
      lock.lock();
      try{
          while(size() == 0)
              notEmpty.await();
          remove();
      }
      finally {
          lock.unlock();
      }
  }


任何帮助将是巨大的!谢谢。

最佳答案

我认为您应该考虑使用“ java.util.Stack”。

Java堆栈已经同步,并且具有pop()和push()方法,您可以从take()和put()调用它们而不必担心锁。

现在,您需要做的就是在take()中等待,如果堆栈对象为空,则可以为堆栈对象设置一个侦听器,或者初始化一个类参数
int takeCalled = 0
并在每次使用空堆栈调用take()时增加它:

public void take(){
    if (stackObj.isempty()) takeCalled++;
    else stackObj.pop();
}


如果takeCalled > 0然后在put()中进行简单检查以清空堆栈

public void put(x){
    stackObj.push(x);
    while(!stackObj.isEmpty()) take();
}


我总是更喜欢使用同步构建中的实现,因为您不能授予免费的错误逻辑。例如,如果first != null,则您的看跌期权将不会释放锁定。

关于java - 条件变量和锁的使用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34475170/

10-11 21:34