(Java) 使用对象的wait()和notify()实现线程安全性

huangapple go评论76阅读模式
英文:

(Java) Thread safety using Object wait() and notify()

问题

以下是您提供的内容的翻译:

我正在寻找一种方法,使一个线程等待/休眠,直到另一个线程发出信号表示某个东西已经准备好。等待的线程应该唤醒,处理可用的数据,然后再次进入休眠,直到另一个线程再次发出信号。

我找到的最简单的方法是使用Object.wait()Object.notify(),它们的行为类似于一个初始值为0的信号量。然而,在notify/wait周围没有synchronized语句的情况下,当线程不是监视器所有者时,Java总是会抛出IllegalMonitorStateException。因此,我简单地将它们放在像下面展示的代码周围。

线程1:运行无限循环

public class Main {
    private Handler handler; // 只有一个实例(单例模式)

    public void listen() {
        while (true) {
            try {
                synchronized (handler) { 
                    handler.wait();
                    int value = handler.getSize();
                    // 做一些事情
                }
            } catch (InterruptedException e) {
                // ...
            }
        }
    }
}

线程2:其他某个类调用removeItem

public class Handler {

    // 单例模式 - 只有一个实例

    private ArrayList<Integer> sharedList;

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

    public void addItem(Integer i) {
        synchronized (sharedList) {
            // 添加到列表
        }
    }

    public void removeItem(int i) {
        synchronized (sharedList) {
            // 删除项目

            // 通知某些内容已被移除
            synchronized (this) {
                this.notify(); // this == handler
            }
        }
    }

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

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

英文:

I was looking for a way to make one thread wait/sleep until another thread signalled that something was ready. The waiting thread should wake up, process the data that was made available, then go back to sleep until the other thread signalled again.

The simplest method I could find was Object.wait() and Object.notify(), which behaved like a semaphore initialised to value 0. However, without the synchronized statements around notify/wait, Java always threw IllegalMonitorStateException when the thread was not the monitor owner. So I simply put them around the code like shown below.

THREAD 1: running infinite loop

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) {
                // ...
            }
        }
    }
}

THREAD 2: Some other class calls removeItem

public class Handler {

    // SINGLETON PATTERN - ONLY ONE INSTANCE

    private ArrayList&lt;Integer&gt; sharedList;

    private Handler() {
        sharedList = new ArrayList&lt;&gt;();
    }

    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();
        }
    }
}

It seems to work perfectly fine but not sure if there is a hidden bug.
My question is: Is this safe? Does wait release the instance lock for handler/this so notify can acquire the lock?

答案1

得分: 1

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

removeItem中存在双重锁定,您必须小心,因为您锁定了两个对象。如果您确实需要这样做,必须确保始终以相同的顺序锁定它们,否则可能会导致死锁。

英文:

Synchronized blocks are safe. The statement synchronized(obj) acquires the lock of the argument obj, so you can call wait and notify on it. They both require that the current thread holds the lock on the object.

You have to be careful about the double-locking you have in removeItem where you lock two objects. If you ever need this, you have to make sure that you always lock them in the same order, otherwise, you may create a deadlock.

huangapple
  • 本文由 发表于 2020年4月6日 23:13:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/61062991.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定