线程安全切换Linked-List节点而不锁定整个列表

时间:2016-05-25 22:58:14

标签: java multithreading synchronization deadlock starvation

我正在学习线程,锁等等。因此,我不想使用synchronized关键字或thread-safe以外的任何类semaphore ReentrantLockLinkedList<T>(没有原子变量)。

我希望Node<T>的同步T类似,按T的大小排序(假设implementsinterface和{{1}具有sizeincrement函数以及lockunlock函数的}。我希望能够用Nodes函数替换两个T.getSize()而不锁定所有列表。

例如,如果我只有一个线程,那么该函数将是&#34; classic&#34;替换功能,类似的东西:

public void IncrementAndcheckReplace(Node<T> node)
{
    node.getData().incrementSize();
    Node nextNode = node.getNext();
    if(nextNode == null)
        return;
    while(node.getData().getSize() > nextNode.getData().getSize())
     {
        node.getPrev().setNext(nextNode);
        nextNode.setPrev(node.getPrev());
        Node nextnext = nextNode.getNext();
        nextNode.setNext(node);
        node.setPrev(nextNode);
        node.setNext(nextnext);
        nextnext.setPrev(node);

        nextNode = node.getNext();
        if(nextNode == null)
            break; 
    }

}

现在让我们来解决同步问题。

我考虑尝试做类似的事情为lock创建Nodes

public void IncrementAndcheckReplace(Node<T> node)
{
    node.lock(); //using fair ReentrantLock for specific node       
    node.getData().incrementSize();
    Node nextNode = node.getNext();
    if(nextNode == null)
    {
        node.unlock();
        return;
    }
    nextNode.lock();
    while(node.getData().getSize() > nextNode.getData().getSize())
     {
        Node prev = node.getPrev();
        if(prev != null)
        {
            prev.lock();
            prev.setNext(nextNode);
        }
        nextNode.setPrev(prev);
        Node nextnext = nextNode.getNext();
        if(nextnext != null)
        {
            nextnext.lock();
            nextnext.setPrev(node);
        }
        nextNode.setNext(node);
        node.setPrev(nextNode);
        node.setNext(nextnext);
        if(prev!=null)
            prev.unlock();
        if(nextnext!=null)
            nextnext.unlock();
        nextNode.unlock();

        nextNode = node.getNext();
        if(nextNode == null)
            break;
        nextNode.lock();
    }
    node.unlock();
}

问题是这不是所有线程安全的,并且可能发生死锁。例如假设我们有Node a, Node b a.next == b and b.prev==a现在如果线程A试图在a上使用替换函数,而线程B试图在b上使用替换函数,它们都将被锁定并且我将无处可去。

如何在没有thread safe整个列表的情况下将替换函数设为lock?我想避免dead-lockstarvation

谢谢!

1 个答案:

答案 0 :(得分:1)

允许最大并发性的最常见答案是锁定重新排序中涉及的所有四个节点。在它们全部被锁定之后,检查排序是否没有改变 - 如果有的话可能中止并重试 - 然后进行重新排序,然后以相反的顺序释放锁。

棘手的部分是,为了避免死锁,必须根据某些固定顺序按顺序锁定节点。不幸的是,按列表中的位置排序它们将不起作用,因为这种排序可能会改变。节点的hashCode和identityHashCode不能保证工作,因为可能存在冲突。您需要提供自己的一些排序,例如通过为每个节点提供一个唯一的构造永久ID,然后可以用于锁定顺序。