左舷之风 2021-07-28 03:10 采纳率: 100%
浏览 73
已结题

关于生产者消费者模式交替输出奇数偶数(利用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
*/
  • 写回答

1条回答 默认 最新

  • 没事干写博客玩 2021-07-28 06:43
    关注

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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 8月5日
  • 已采纳回答 7月28日
  • 创建了问题 7月28日

悬赏问题

  • ¥15 MATLAB和mosek的求解问题
  • ¥20 修改中兴光猫sn的时候提示失败
  • ¥15 java大作业爬取网页
  • ¥15 怎么获取欧易的btc永续合约和交割合约的5m级的历史数据用来回测套利策略?
  • ¥15 有没有办法利用libusb读取usb设备数据
  • ¥15 为什么openeluer里面按不了python3呢?
  • ¥15 关于#matlab#的问题:训练序列与输入层维度不一样
  • ¥15 关于Ubuntu20.04.3LTS遇到的问题:在安装完CUDA驱动后,电脑会进入卡死的情况,但可以通过键盘按键进入安全重启,但重启完又会进入该情况!
  • ¥15 关于#嵌入式硬件#的问题:树莓派第一天重装配置python和opencv后第二天打开就成这样,瞎捣鼓搞出来文件夹还是没把原来的界面调回来
  • ¥20 Arduino 循迹小车程序电路出错故障求解