首页 > 解决方案 > (Java) 使用 Object wait() 和 notify() 的线程安全

问题描述

我一直在寻找一种方法让一个线程等待/休眠,直到另一个线程发出信号表明某事已准备就绪。等待的线程应该唤醒,处理可用的数据,然后回到睡眠状态,直到另一个线程再次发出信号。

我能找到的最简单的方法是Object.wait()and Object.notify(),它的行为类似于初始化为值 0 的信号量。但是,如果没有synchronized周围的语句notify/wait,Java 总是IllegalMonitorStateException在线程不是监视器所有者时抛出。所以我只是把它们放在代码周围,如下所示。

线程1:运行无限循环

public class Main {
    private Handler handler; // only one instance (singleton pattern)

    public void listen() {
        while (true) {
            try {
                synchronized (handler) { 
                    handler.wait();
                    int value = handler.getSize();
                    // do something
                }
            } catch (InterruptedException e) {
                // ...
            }
        }
    }
}

线程 2:其他一些类调用 removeItem

public class Handler {

    // SINGLETON PATTERN - ONLY ONE INSTANCE

    private ArrayList<Integer> sharedList;

    private Handler() {
        sharedList = new ArrayList<>();
    }

    public void addItem(Integer i) {
        synchronized (sharedList) {
            // add to list
        }
    }

    public void removeItem(int i) {
        synchronized (sharedList) {
            // remove item

            // notify that something is removed
            synchronized (this) {
                this.notify(); // this == handler
            }
        }
    }

    public int getSize() {
        synchronized (sharedList) {
            return sharedList.size();
        }
    }
}

它似乎工作得很好,但不确定是否存在隐藏的错误。我的问题是:这安全吗?是否wait释放实例锁handler/this以便notify获取锁?

标签: javamultithreadingconcurrency

解决方案


同步块是安全的。该语句synchronized(obj)获取参数的锁,obj因此您可以调用它。它们都要求当前线程持有对象上的锁。waitnotify

您必须小心removeItem锁定两个对象的双重锁定。如果你需要这个,你必须确保你总是以相同的顺序锁定它们,否则,你可能会造成死锁。


推荐阅读