一个很简单的生产者消费者模型,但是搞不懂为什么报错了。
锁的对象是LOCK时,可以正常跑,当我把锁的对象改为count本身的时候,就报错了。
报错信息:
当前数量: 0 ,消费者等待...
当前数量: 1 ,生产者生产完毕!
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.notifyAll(Native Method)
at TestProducterCunsumer$Producter.run(TestProducterCunsumer.java:61)
at java.lang.Thread.run(Thread.java:748)
代码:
/**
* ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
* & | | | | * * * * | | | | &
* & | | | | * * * * | | | | &
* & | -------- | * * * * | -------- | &
* & | -------- | * * | -------- | &
* & | | | | * * * * | | | | &
* & | | | | * * * * | | | | &
* & | | | | * * * * | | | | &
* $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
*/
/**
* Created by HXH on 2021/3/18
*
* @desc
*/
public class TestProducterCunsumer {
//锁count报错
public static Integer count = 0;
//锁LOCK 正常
private static String LOCK = "lock";
public static void main(String[] args) {
TestProducterCunsumer testProducterCunsumer = new TestProducterCunsumer();
// Producter producter = testProducterCunsumer.new Producter();
// Cunsumer cunsumer = testProducterCunsumer.new Cunsumer();
Producter producter = new Producter();
Cunsumer cunsumer = new Cunsumer();
Thread producterThread = new Thread(producter);
Thread cunsumerThread = new Thread(cunsumer);
producterThread.start();
cunsumerThread.start();
}
//生产者
static class Producter implements Runnable {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (count) {
if (count > 0) {
try {
System.out.println("当前数量: " + count + " ,生产者等待...");
count.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count++;
System.out.println("当前数量: " + count + " ,生产者生产完毕!");
count.notifyAll();
System.out.println("已通知消费者来消费!");
}
}
}
}
// 消费者
static class Cunsumer implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (count) {
while (true) {
if (count <= 0) {
System.out.println("当前数量: " + count + " ,消费者等待...");
try {
count.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("当前数量: " + count + " ,消费者消费!");
count--;
count.notifyAll();
System.out.println("已通知生产者来生产!");
}
}
}
}
}
1、synchronized 简单点理解就是查询及修改一个对象实例的对象头中的标志位,两个线程要锁同一个对象才能实现同步。
2、生产者执行count++后,count变量实际上指向了另外一个对象,然而生产者线程并不持有新对象的锁,所以会在执行count.notifyAll时报IllegalMonitorStateException。
3、使用synchronized (count.toString().intern())报错原理也是一样,生产者执行count++后,count.toString().intern()或count实际上也会指向另外一个对象。所以会在执行count.toString().intern().notifyAll或count.notifyAll时报IllegalMonitorStateException。
4、如果先定义 private static String cintern = count.toString().intern(); 再锁cintern 对象就行可以。就是因为生产者执行count++后,cintern变量并不会改变,当前线程持有cintern指向的对象的锁,执行cintern.notifyAll自然不会报错。
换成这个 synchronized (count.toString().intern())
补充下:count变化时,锁就会消失,就会没有同步效果。