彩虹海呐-
2021-03-19 11:57
采纳率: 100%
浏览 43
已采纳

java多线程锁的对象不能改变其值吗

一个很简单的生产者消费者模型,但是搞不懂为什么报错了。

锁的对象是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("已通知生产者来生产!");
                }
            }

        }
    }
}
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • 规则边缘 2021-03-19 17:47
    已采纳

    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自然不会报错。

    已采纳该答案
    1 打赏 评论
  • 换成这个  synchronized (count.toString().intern())

    补充下:count变化时,锁就会消失,就会没有同步效果。

    打赏 评论

相关推荐 更多相似问题