关于生产者消费者模式交替输出奇数偶数(利用Integer)出异常

关于生产者消费者模式交替输出奇数偶数(利用Integer)出异常

问题描述:

Java中使用生产者消费者模式实现数字交替输出。使用Integer包装类出异常。

这里用的是老杜的题b站视频

我怀疑是Integer包装类是线程安全的,会导致锁出问题,导致t1线程锁没有了。
希望看到的网友能分析一下原理……

代码

package com.zuoxianzhifeng.study.thread.temp;

/**
 * 1、使用生产者和消费者模式实现,交替输出:
 *     假设只有两个线程,输出以下结果:
 *         t1-->1
 *         t2-->2
 *         t1-->3
 *         t2-->4
 *         t1-->5
 *         t2-->6
 *         ....
 *
 *         要求:必须交替,并且t1线程负责输出奇数。t2线程负责输出偶数。
 *         两个线程共享一个数字,每个线程执行时都要对这个数字进行:++
 *
 */
public class Homework2 {
    public static void main(String[] args) throws InterruptedException {
        Integer integer = 1;
        //new线程 关联同一个Integer对象
        Thread t1 = new Thread(new MyRunnableA(integer));
        Thread t2 = new Thread(new MyRunnableB(integer));
        //重命名
        t1.setName("t1-->");
        t2.setName("t2-->");
        //执行
        t2.start();
        t1.start();


    }
}

//奇数线程
class MyRunnableA implements Runnable{
    //定义共享对象
    Integer integer;

    public MyRunnableA(Integer integer) {
        this.integer = integer;
    }

    @Override
    public void run() {
        while (true){

            synchronized (integer){
                if (integer % 2 == 0){//如果integer现在是偶数

                    try {
                        integer.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //代码执行到这里 integer是奇数 可以打印输出
                System.out.println(Thread.currentThread().getName()+integer);
                integer ++;//现在integer是偶数了 严重怀疑这里出问题了
                //代码执行到这里 integer是偶数 唤醒偶数线程
                integer.notify();
                //代码执行到这里 本奇数线程释放锁
            }
        }
    }

}

//偶数线程
class MyRunnableB implements Runnable{
    //定义共享对象
    Integer integer;

    public MyRunnableB(Integer integer) {
        this.integer = integer;
    }

    @Override
    public void run() {
        while (true){
            synchronized (integer){
                if (integer % 2 == 1){//如果integer现在是奇数
                    try {
                        integer.wait();//偶数线程进入等待 并且释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //代码执行到这里 integer是偶数 可以打印输出
                System.out.println(Thread.currentThread().getName()+integer);
                integer ++;//现在integer是奇数了 严重怀疑这里出问题了
                //代码执行到这里 integer是奇数 唤醒奇数线程
                integer.notify();
                //代码执行到这里 本偶数线程释放锁
            }
        }
    }

}


/*
t1-->1
Exception in thread "t1-->" java.lang.IllegalMonitorStateException: current thread is not owner
    at java.base/java.lang.Object.notify(Native Method)
    at com.zuoxianzhifeng.study.thread.temp.MyRunnableA.run(Homework2.java:65)
    at java.base/java.lang.Thread.run(Thread.java:832)
*/

我这边自己写了个类
在线程run方法中使用myInteger.i的方式访问i
实现了想要效果

class MyInteger{
    public int i = 1;
}
/*
  t1-->27365
  t2-->27366
  t1-->27367
  t2-->27368
  t1-->27369
*/

并不是,是你两个线程传入的是两个不同runable,Integer在两个不同的runable内各自有一份,所以你相当于没有锁。。。。。java属于引用传递,你传进去后,并不是说在new后经过构造函数那俩integer地址相同,解决办法只使用一个runable对象,不要new 2个出来,逻辑写在一起,另一个就是你自己的解决方式,因为你访问的.i是唯一的,要锁的对象必须是唯一的,否则无意义