Java 等待/通知死锁
我在“Add”和“Get”方法中有一个带有阻塞机制的队列,其中第一个线程添加数据,第二个线程获取数据Java 等待/通知死锁,java,multithreading,deadlock,wait,Java,Multithreading,Deadlock,Wait,我在“Add”和“Get”方法中有一个带有阻塞机制的队列,其中第一个线程添加数据,第二个线程获取数据 public synchronized MyObj getData() { synchronized (myLock) { synchronized (this) { if (isEmpty()) { wait(0);
public synchronized MyObj getData() {
synchronized (myLock) {
synchronized (this) {
if (isEmpty()) {
wait(0);
}
}
return getData();
}
}
public synchronized void addData(MyObj data) {
if (!isFull()) {
putData(data);
synchronized (this) {
notify();
}
}
}
在上面的代码中,如果第一个线程试图获取数据,而队列为空,我将通过wait(0)进行等待,直到另一个线程通过notify()将数据添加到队列中,以释放等待
现在,我想在队列已满且有人试图向其添加更多数据时添加另一个“锁”:
public synchronized MyObj getData() {
synchronized (myLock) {
synchronized (this) {
if (isEmpty()) {
wait(0);
}
}
synchronized (this) {
notify();
}
return getData();
}
}
public synchronized void addData(MyObj data) {
synchronized (myLock) {
synchronized (this) {
if (isFull()) {
wait(0);
}
}
}
synchronized (this) {
notify();
}
PutData(data);
}
结果并不是我所期望的,我想我得到了一个死锁,因为进程被卡住了
更新
这是我获取数据的方式:
queueSize--;
startPointer = (startPointer + 1) % mqueueSize;
data = (String) queue[startPointer];
这就是我添加数据的方式
queueSize++;
endPointer = (endPointer + 1) % mqueueSize;
queue[endPointer] = data;
public synchronized boolean isEmpty() {
return queueSize== 0;
}
public synchronized boolean isFull() {
return queueSize== mqueueSize;
}
你为什么不进去看看。也许它在你的情况下会有用
请特别注意,如果在构造函数中指定队列的容量,那么队列将阻塞。为什么不查看。也许它在你的情况下会有用
请特别注意,如果您在构造函数中指定队列的容量,那么队列将阻塞。从方法签名中删除
synchronized
关键字,这意味着您持有整个方法调用的this
监视器--synchronized(this)
块只是多余的
编辑:
…然后在
myLock
上调用wait和notify,而不是this
。并且完全忘记在上同步此
。这是因为在等待时(在当前代码中的This
),您没有释放myLock
锁,因此另一个线程无法访问notify()
从方法签名中删除synchronized
关键字,这意味着您为整个方法调用持有this
监视器--synchronized(this)
块只是冗余的
编辑:
…然后在
myLock
上调用wait和notify,而不是this
。并且完全忘记在上同步此
。这是因为在等待时(在当前代码中的This
),您没有释放myLock
锁,因此另一个线程无法访问notify()
将if
替换为while
。如果集合真的不是空的/不是满的,那么仔细检查也无妨
你真的不需要两把锁。单锁也可以很好地工作,应该简单得多
public synchronized T get()
{
while(isEmpty())
wait(0);
notifyAll();
return super.get();
}
public synchronized put(T t)
{
while(isFull())
wait(0);
super.put(t);
notifyAll();
}
当某些内容发生更改时,所有线程都将唤醒。但是如果他们不能完成他们的工作,他们将等待下一个
通知在期间将如果替换为。如果集合真的不是空的/不是满的,那么仔细检查也无妨
你真的不需要两把锁。单锁也可以很好地工作,应该简单得多
public synchronized T get()
{
while(isEmpty())
wait(0);
notifyAll();
return super.get();
}
public synchronized put(T t)
{
while(isFull())
wait(0);
super.put(t);
notifyAll();
}
当某些内容发生更改时,所有线程都将唤醒。但是如果他们不能完成他们的工作,他们将等待下一个通知为什么有三个同步的语句?wait(0)
仅释放this
上的锁,因此只需保留该锁,并从方法和synchronized(myLock)
中转储synchronized
无论何时调用某个对象上的wait(在本例中,您调用的是this
),该对象上的锁都会自动释放,以允许另一个线程继续。但是您从来没有在myLock
上调用wait(您也不应该这样做,因为您已经在this
上调用了)。该部分是多余的,会导致死锁
考虑这个场景:应该添加的线程在myLock
上获得锁,但发现队列已满,所以等待。此等待不会解除myLock
上的锁定。另一个线程想要获取数据,但无法进入synchronized
块,因为第一个线程没有释放myLock
上的锁
结论:删除synchronized(myLock)
块。为什么有三个synchronized
语句?wait(0)
仅释放this
上的锁,因此只需保留该锁,并从方法和synchronized(myLock)
中转储synchronized
无论何时调用某个对象上的wait(在本例中,您调用的是this
),该对象上的锁都会自动释放,以允许另一个线程继续。但是您从来没有在myLock
上调用wait(您也不应该这样做,因为您已经在this
上调用了)。该部分是多余的,会导致死锁
考虑这个场景:应该添加的线程在myLock
上获得锁,但发现队列已满,所以等待。此等待不会解除myLock
上的锁定。另一个线程想要获取数据,但无法进入synchronized
块,因为第一个线程没有释放myLock
上的锁
结论:删除synchronized(myLock)
块。如前所述,您的代码有太多synchronized
注释。此外,在if
条件中检查等待
开启的条件,但理想情况下应在while
循环中检查该条件以避免。下面是修复这些问题的代码概要
// _isEmpty and _getData are private unsynchronized methods
public MyData get() throws InterruptedException {
// wait and notify should be called from a block
// synchronized on the same lock object (here myLock)
synchronized (myLock) {
// the condition should be tested in a while loop
// to avoid issues with spurious wakeups
while (_isEmpty()) {
// releases the lock and wait for a notify to be called
myLock.wait();
}
// when control reaches here, we know for sure that
// the queue is not empty
MyData data = _getData();
// try to wake up all waiting threads - maybe some thread
// is waiting for the queue not to be full
myLock.notifyAll();
}
}
// _isFull and _putData are private unsynchronized methods
public void put(MyData obj) throws InterruptedException {
synchronized (myLock) {
while (_isFull()) {
myLock.wait();
}
_putData(obj);
myLock.notifyAll();
}
}
如前所述,您的代码有太多的同步的注释。此外,在if
条件中检查等待
开启的条件,但理想情况下应在while
循环中检查该条件以避免。下面是修复这些问题的代码概要
// _isEmpty and _getData are private unsynchronized methods
public MyData get() throws InterruptedException {
// wait and notify should be called from a block
// synchronized on the same lock object (here myLock)
synchronized (myLock) {
// the condition should be tested in a while loop
// to avoid issues with spurious wakeups
while (_isEmpty()) {
// releases the lock and wait for a notify to be called
myLock.wait();
}
// when control reaches here, we know for sure that
// the queue is not empty
MyData data = _getData();
// try to wake up all waiting threads - maybe some thread
// is waiting for the queue not to be full
myLock.notifyAll();
}
}
// _isFull and _putData are private unsynchronized methods
public void put(MyData obj) throws InterruptedException {
synchronized (myLock) {
while (_isFull()) {
myLock.wait();
}
_putData(obj);
myLock.notifyAll();
}
}
为什么单锁就足够了?如果线程试图在一个循环中将数据添加到一个完整的队列中,它会不断地点击“if(!isFull())。@kenny这可能不是必需的,但一般情况下可能有多个线程在等待。为什么单锁就足够了?如果线程将尝试