繁体   English   中英

延迟锁定时,在持有特定监视器的同时修改对象的易失布尔字段有什么处理?

[英]What is the deal with modifying the volatile boolean field of an object, while holding the specific monitor, when lazy locking?

我实现了一个惰性锁定列表,该列表支持以下方法:布尔值add(T项),布尔值remove(T项),布尔值contains(T项)。

例如,add方法:

@Override
public boolean add(T item) {
    int key = item.hashCode();

    while(true){
        Node pred = head;
        Node curr = pred.next;

        while(curr.key < key) { pred = curr; curr = curr.next; }

        pred.Lock.lock();
        curr.Lock.lock();

        try{
            if(!pred.marked && !curr.marked && pred.next == curr){
                if(curr.key == key){ return false; }
                else{ Node insertMe = new Node(item); insertMe.next = curr; pred.next = insertMe; return true; }
            }
        } finally{ pred.Lock.unlock(); curr.Lock.unlock(); }
    }
}

如果Node对象具有一个“标记”为易失性布尔字段,则默认情况下设置为false。 节点的锁是可重入的。 标记为true的节点被视为已经由remove方法删除。 但是,当特定对象的监视器仍然由特定线程持有时,为什么这甚至相关? 换句话说,线程是否正在随时获取对象的锁,然后看到该节点被标记为已删除,甚至会发生?

编辑:contains方法显然根本不会锁定,但是将标记为已删除的节点的目的仅仅是为了能够进行一次contains检查? 因此,有必要将标记字段声明为volatile吗?

包含:

    @Override
public boolean contains(T item) {
    int key = item.hashCode();

    while(true){
        Node curr = head;

        while(curr.key < key) { curr = curr.next; }

        if(curr.key == key && !curr.marked) return true;
        else return false;
    }
}

去掉:

    @Override
public boolean remove(T item) {
    int key = item.hashCode();

    while(true){
        Node pred = head;
        Node curr = pred.next;

        while(curr.key < key) { pred = curr; curr = curr.next; }

        pred.Lock.lock();
        curr.Lock.lock();

        try{
            if(!pred.marked && !curr.marked && pred.next == curr){
                if(curr.key != key) { return false; }
                else{
                    curr.marked = true;
                    pred.next = curr.next;
                    return true;
                }
            }
        } finally{ pred.Lock.unlock(); curr.Lock.unlock(); }
    }
}

在您的情况下, marked是包含方法而不是添加方法必需的。 我的猜测是,添加功能中marked -check的绝对不起作用。

marked字段绝对必须是易变的,因为JIT保留重新排序代码的权利(如果这样做会带来好处)。 唯一的保证是,在更改易失性字段之前,任何对易失性字段进行任何操作之前的代码都已完全执行(发生在关系之前)。

因此,在上面的代码中,如果字段不是可变的,则JIT可以决定在调用“包含”的线程中创建marked的线程本地副本,然后再检查该marked本地版本,但是该版本可能已过时那一点。 在这种情况下,同时运行containsremove可能会导致竞争状况。

作为附带说明,应该提到Concurrent包中的Collections解决所有这些问题的方式更加优雅(并且没有bug),因此,在所有情况下均应优先考虑。 如果复制标准库中已经存在的类,则通常会更糟地实现它。

暂无
暂无

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

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