美文网首页
Effective Java - 避免过度同步

Effective Java - 避免过度同步

作者: DZQANN | 来源:发表于2022-09-11 19:49 被阅读0次

第79条 避免过度同步

  1. 在一个被同步的区域内部,不要调用设计成要被覆盖的方法,或者是由客户端以函数对象的形式提供的方法

  2. 死锁的例子:

    public class ObservableSet<E> extends ForwardingSet<E> {
        public ObservableSet(Set<E> set) { super(set); }
        private final List<SetObserver<E>> observers = new ArrayList<>();
        public void addObserver(SetObserver<E> observer) {
            synchronized(observers) {
                observers.add(observer);
            }
        }
        public boolean removeObserver(SetObserver<E> observer) {
            synchronized(observers) {
                return observers.remove(observer);
            }
        }
        private void notifyElementAdded(E element) {
            synchronized(observers) {
                for (SetObserver<E> observer : observers)
                    observer.added(this, element);
            }
        }
        @Override public boolean add(E element) {
            boolean added = super.add(element);
            if (added)
                notifyElementAdded(element);
            return added;
        }
        @Override public boolean addAll(Collection<? extends E> c) {
            boolean result = false;
            for (E element : c)
                result |= add(element); // Calls notifyElementAdded
            return result;
        }
    }
    
    set.addObserver(new SetObserver<>() {
        public void added(ObservableSet<Integer> s, Integer e) {
            System.out.println(e);
            if (e == 23) {
                ExecutorService exec = Executors.newSingleThreadExecutor();
                try {
                    exec.submit(() -> s.removeObserver(this)).get();
                } catch (ExecutionException | InterruptedException ex) {
                    throw new AssertionError(ex);
                } finally {
                    exec.shutdown();
                }
            }
        }
    });
    

    这时候优于执行到这里的时候会去原list里面remove,而这时候原list已经被锁了,就会造成死锁

  3. 由于 Java 程序设计语言中的锁是可重入的,所以两次进入同一个锁的同步代码块调用不会死锁

  4. CopyOnWriteArrayList过重新拷贝整个底层数组,进而实现所有的修改操作

  5. 应该在同步区域内做尽可能少的工作

思考

  1. 死锁是一定需要注意的,它不会抛出任何异常,只会让所有的线程都处于阻塞状态,后续发现和排查问题都比较困难
  2. CopyOnWriteArrayList虽然可以避免很多多线程问题,但是在对于写操作特别频繁的场景下,CopyOnWriteArrayList的性能会下滑的非常严重,如果写操作非常多,使用CopyOnWriteArrayList需要慎重考虑

相关文章

网友评论

      本文标题:Effective Java - 避免过度同步

      本文链接:https://www.haomeiwen.com/subject/gsoqortx.html