代码之家  ›  专栏  ›  技术社区  ›  overexchange

客户端锁定是否违反了同步策略的封装?

  •  3
  • overexchange  · 技术社区  · 7 年前

    如所述 Java_author

    客户端锁定需要保护客户端代码,该代码使用一些带有锁的对象X,X用于保护其自身的状态。


    list . 如上所述,使用 ListHelper 键入要同步的对象 putIfAbsent() ,是一个错误的锁。

    package compositeobjects;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class ListHelper<E> {
    
        private List<E> list =
                        Collections.synchronizedList(new ArrayList<E>());
    
    
        public boolean putIfAbsent(E x) {
            synchronized(list){
                boolean absent = !list.contains(x);
                if(absent) {
                    list.add(x);
                }
                return absent;
            }
        }
    }
    

    但是,Java作者说,

    违反 同步策略的封装。

    我的理解是,嵌套类实例 Collections.synchronizedList() 列表 对象


    )在 ListHelper ,违反了同步策略的封装?

    2 回复  |  直到 7 年前
        1
  •  3
  •   Andy Turner    7 年前

    你所依赖的事实是 synchronizedList 将自身用作监视器,这在目前是正确的。

    你甚至相信这样一个事实 synchronized 为了实现同步,目前这也是正确的(这是一个

    有几种方法可以实现


    the constructor of synchronizedList :

    SynchronizedList(List<E> list) {
      super(list);
      // ...
    }
    

    可以更改为

    SynchronizedList(List<E> list) {
      super(list, new Object());
      // ...
    }
    

    mutex 中方法使用的字段 SynchronizedList 实施不再是 this (有效),因此在外部同步 list 将不再工作。


    ,使用 synchronized (list) 是否具有预期效果在 Javadoc ,所以这个行为 不会

        2
  •  0
  •   M. le Rutte    7 年前

    您的代码基本上创建了一个同步集。它仅在列表中不存在的情况下添加元素 set .

    无论同步列表如何进行自己的锁定,您的代码必须提供自己的锁定机制,因为有两个对同步列表的调用,其中列表之间将释放其锁。因此,如果两个线程添加同一个对象,它们都可以传递 contains 选中并将其添加到列表中。化合物 synchronize 确保它不是。最重要的是,所有列表使用代码都要通过实用程序类,否则它仍然会失败。

    正如我在评论中所写的那样,使用 synchronized set


    编辑:

    如果您的代码需要一个列表而不是一个集合 LinkedHashSet 不是我自己创建一个新的同步列表的选项:

    public class SynchronizedList<E> implements List<E> {
        private List<E> wrapped = new ArrayList<E>();
    
        ....
        @override
        public int size() {
           synchronized(this) {
              return wrapped.size();
           }
       }
    
       ....
       @override
       public void add(E element) {
        synchronized(this) {
            boolean absent = !wrapped.contains(x);
            if(absent) {
                wrapped.add(element);
            }
            return absent;
        }
    }