美文网首页
java19(多线程--05 经典案例之生产者和消费者问题分析)

java19(多线程--05 经典案例之生产者和消费者问题分析)

作者: 机智的老刘明同志 | 来源:发表于2019-01-16 08:12 被阅读135次

            如下图代码所示,生产者Producer类和消费者Consumer类共同操作同一个资源resource,二者产生了如下所示的线程安全问题

    分析:

            上面的例子中,我们开启了4个线程,其中线程t1,t2是生产者。t3,t4是消费者

        (1)线程t1正常生产后进入阻塞状态   

            假设开始的时候:t1进入resource类中,flag初始值为false,t1直接给name赋值,然后执行notify()(线程池此时为空)。此时t1还处于运行状态,因此run方法还会从头再执行,而此时flag变为true,t1进入阻塞状态wait()

        (2)线程t2进入阻塞状态

            当线程t1进入阻塞状态后,此时t2,t3,t4线程都处于就绪状态。这里我们假设t2进入运行状态,此时flag为真,t2也进入阻塞状态wait()

        (3)线程t3正常消费后进入阻塞状态,并唤醒线程t1

            t3正常消费,唤醒线程池中的t1(此时t1处于就绪状态)t3还处于运行状态,flag变为false,t3进入阻塞状态wait()

        (4)线程t1与线程t4争抢执行权,t4进入阻塞状态

            由于flag为false,线程t4进入阻塞状态。线程t1开始执行

        (5)t1正常生产,唤醒最早进入线程池中的t2,并进入阻塞状态

        (6)t2异常生产

            此时线程中仅剩t2处于就绪状态,t2不会重新判断flag,而是继续执行wait()之后的代码    

    解决方案1:追加自旋锁

            判断flag真假可以使用 while (condition) {},不能使用 if(condition) {}。其中 while(condition)循环,它又被叫做“自旋锁”。为防止该线程没有收到notify()调用也从wait()中返回(也称作虚假唤醒),这个线程会重新去检查condition条件以决定当前是否可以安全地继续执行还是需要重新保持等待,而不是认为线程被唤醒了就可以安全地继续执行了。被唤醒的线程会自旋直到自旋锁(while循环)里的条件变为false(这种做法要慎重,目前的JVM实现自旋会消耗太大的CPU)

    解决方案2: JDK1.5版本新特性

            ReentrantLock(重入锁):效果synchronized一样,都可以同步执行,lock方法获得锁,unlock方法释放锁

            Condition类的awiat方法和Object类的wait方法等效

            Condition类的signal方法和Object类的notify方法等效

            Condition类的signalAll方法和Object类的notifyAll方法等效

    相关文章

      网友评论

          本文标题:java19(多线程--05 经典案例之生产者和消费者问题分析)

          本文链接:https://www.haomeiwen.com/subject/xzcedqtx.html