在多线程Java中检测到不合理的死锁
我有一段代码,其中两个实现Runnable的线程类正在运行并共享一个类Buffer的公共对象 虽然据我所知,我已经正确地使用了同步块和在多线程Java中检测到不合理的死锁,java,multithreading,synchronization,thread-safety,deadlock,Java,Multithreading,Synchronization,Thread Safety,Deadlock,我有一段代码,其中两个实现Runnable的线程类正在运行并共享一个类Buffer的公共对象 虽然据我所知,我已经正确地使用了同步块和wait()和notify()方法,但是当我在try/catch块中使用thread.sleep(0)睡眠线程时,在一些接受的输出结果之后,它将进入死锁 当我用1000ms(即thread.sleep(1000)睡眠线程烹调,用3000ms(即thread.sleep(3000)睡眠线程Bheem时,未检测到问题 这是线程中常见的生产者-消费者场景,我有意将消费者
wait()
和notify()
方法,但是当我在try/catch块中使用thread.sleep(0)
睡眠线程时,在一些接受的输出结果之后,它将进入死锁
当我用1000ms(即thread.sleep(1000)
睡眠线程烹调,用3000ms(即thread.sleep(3000)
睡眠线程Bheem时,未检测到问题
这是线程中常见的生产者-消费者场景,我有意将消费者置于生产者之上
p.S.-我已经给出了上一次调整后的输出。实际产量相当大。
public void consume() {
while (ob.buffer >= 1) {
synchronized (ob) {
System.out.println(Thread.currentThread().getName()
+ " started eating Ladoos with currently "
+ (ob.buffer--) + " ladoos in plate");
try {
Thread.sleep(0); // bheem takes 1.5 sec to eat
ob.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
synchronized (ob) {
try {
System.out
.println("Plate is empty, bheem will wait for ladoos to serve ");
ob.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run() {
while (true) {
consume();
}
}
以下代码属于Bheem类别
public void consume() {
while (ob.buffer >= 1) {
synchronized (ob) {
System.out.println(Thread.currentThread().getName()
+ " started eating Ladoos with currently "
+ (ob.buffer--) + " ladoos in plate");
try {
Thread.sleep(0); // bheem takes 1.5 sec to eat
ob.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
synchronized (ob) {
try {
System.out
.println("Plate is empty, bheem will wait for ladoos to serve ");
ob.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run() {
while (true) {
consume();
}
}
这个在烹饪课上
public void produce() {
while (ob.buffer < 5) {
synchronized (ob) {
System.out.println(Thread.currentThread().getName()
+ " started making Ladoos with currently "
+ (ob.buffer++) + " ladoos in plate");
try {
Thread.sleep(0); // 1 sec time taken to make a ladoo
ob.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
synchronized (ob) {
try {
System.out.println("Plate is full, cook will wait ");
ob.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run() {
while (true) {
produce();
}
}
输出
Plate is empty, bheem will wait for ladoos to serve
Cook started making Ladoos with currently 0 ladoos in plate
Bheem started eating Ladoos with currently 1 ladoos in plate
Plate is empty, bheem will wait for ladoos to serve
Cook started making Ladoos with currently 0 ladoos in plate
Bheem started eating Ladoos with currently 1 ladoos in plate
Plate is empty, bheem will wait for ladoos to serve
Cook started making Ladoos with currently 0 ladoos in plate
Bheem started eating Ladoos with currently 1 ladoos in plate
Plate is empty, bheem will wait for ladoos to serve
Cook started making Ladoos with currently 0 ladoos in plate
Bheem started eating Ladoos with currently 1 ladoos in plate
Cook started making Ladoos with currently 0 ladoos in plate
Cook started making Ladoos with currently 1 ladoos in plate
Cook started making Ladoos with currently 2 ladoos in plate
Cook started making Ladoos with currently 3 ladoos in plate
Cook started making Ladoos with currently 4 ladoos in plate
Plate is full, cook will wait
Plate is empty, bheem will wait for ladoos to serve
当消费者接受最后一个ladoo时,是什么阻止了你的制作人在消费者设法调用
wait()
之前完全填满盘子并调用最后一个notify()
?同样,当盘子装满时,是什么阻止消费者在制作人进入wait()
之前拿走最后一个ladoo并调用最后一个notify()
如果其他线程没有等待接收通知,则调用
o.notify()
不会执行任何操作。也就是说,对象o
不记得它收到了通知。为了简化您的生活,请查看java.util.concurrent
package@rkosegi是的,但即使是在实验中,这种荒谬的结果也应该有一些原因,至少有一个错误是您正在同步块外读取ob.buffer
。您不仅会错过更新(除非声明为volatile),而且同步块中的状态也无法保证。此外,您的等待条件没有得到适当的保护。您只需输入等待,而不知道缓冲区的状态。等待应该在条件循环下的同步块内完成(您可能会有虚假的唤醒)。我建议阅读《实践中的并发》一书,因为书中还有很多内容。@MPlatvoet我刚刚将while(ob.buffer<5){
与synchronized(ob)进行了交换{
在Bheem类中也一样。仍然是相同的死锁。您的意思是,当jvm从Cook类中while循环的最后一次迭代转移到Cook类中的下一个同步块时,**在这个转移时间之间**消费者线程从等待状态被Cook线程最后接受的while循环迭代的ob.notify()唤醒;
并进行5次迭代,然后,当Cook类中的立即下一个同步块运行并调用其wait()方法从而释放锁时,使用者的while条件循环的立即下一个同步块运行并调用wait()也会导致死锁情况,因为双方都在等待对方?这就是你想说的?如果我错了,请纠正我。@angrysumit,是:消费者线程清空盘子,离开同步块,丢失其时间片。生产者线程进入同步块,开始填充盘子,调用notify()在每个ladoo.Consumer线程之后,尝试进入第二个同步块,但无法。生产者线程离开同步块。Consumer线程进入第二个同步块,调用wait(),最终永远等待。Consumer线程进入第二个同步块,调用wait(),永远等待。那么什么样的解决方案可以避免这种情况呢?@angrysumit,请阅读Oracle Java教程中关于保护块的内容。基本上,wait()/notify()的全部目的就是实现所谓的保护块: