人生三从境界:昨夜西风凋碧树,独上高楼,望尽天涯路。 衣带渐宽终不悔,为伊消得人憔悴。 众里寻他千百度,蓦然回首,那人却在灯火阑珊处。

狂神说《多线程》卖早餐设置互斥锁

1. 先说一下为什么会出现一份早餐被多个窗口同时售卖,并且有时还会出现-1

  首先我先调整一下代码

  

 

  this.breakfast的加法不写在一起,单独成立一行,出现重复票与-1的情况更容易,(采用方式二:实现Runable接口的情况下)由于线程对共享资源(也就是早餐数)的消耗十分短暂,

且一个线程本身执行的就很快,无法保证下一个售卖窗口(线程)在做加法(原视频用的减法)时breakfast数量是正确的,线程的启动无法控制,由cup调度决定。因此就得设置线程锁(网上查到是互斥锁)

2. 完整代码(注释也挺多的,新人见解欢迎纠错)

  *************************说明一点:每次运行的结果是不一样的,我常看到弹幕里说龟兔赛跑的事,一个结果多运行几次,效果是不一样的!*******************************************

 

package com.cy.Thread;


/**
 * 初识并发问题,三个窗口共卖10分早餐
 */

import com.sun.org.apache.xerces.internal.util.SynchronizedSymbolTable;

/**
 * 本机i5 6400只有4核心4线程
 * 创建线程方式2:实现Runable接口,执行线程需丢入Runable的实现类
 */
public class TestThread3 implements Runnable{
    private int breakfast =1;
    private boolean tag = true;// 标记为了停止线程


    @Override
    public void run() {
        while(this.tag){
            //非同步售卖
//            saleBreakfast1();

            //同步售卖
            saleBreakfast2();
        }
    }

    public static void main(String[] args) {

        //创建Runable接口的实现类对象
        TestThread3 thread =new TestThread3();

        /**
         * 得有一个公共变量,也就是breakfast
         * 简洁写法(属于代理模式,相当于中介,前提是均得实现同一个接口)
         * 实现Runable可以达到同一个任务多线程执行,当然也可以像继承Thread那样各自完成各自的(多个干爹,所有工作共同承担)
         * 继承Thread 就只能各自完成各自的(只能有一个亲爹,所有工作一人来)
         */
         Thread t1 = new Thread(thread,"一号窗口");
         Thread t2 = new Thread(thread,"二号窗口");
         Thread t3 = new Thread(thread,"三号窗口");


         t1.start();
         t2.start();
         t3.start();
    }

    //不同步,可能同时卖同一份早餐,有可能最后还有一张票时候三者都操作导致得到0与-1
    public void saleBreakfast1(){
        while(true){
            //设置15份更容易三个窗口都出现,更直观
            if(this.breakfast > 15){  
                break;
            }
            /**
             * 模拟延迟
             */
            try {
                Thread.sleep(200);   //毫秒   1秒等于1000毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"在卖早餐---》"+(this.breakfast));
            /**
             * 这里不写成breakfast++,而是单独一行是为了重现线程不同步导致的breakfast被重复售卖
             * 因为你在做减法时,其他线程因为runable共享资源的原因就可能已经开始卖早餐了,因此得设置线程锁(互斥锁)
             */
            this.breakfast++;

        }
    }

    //互斥锁
    public void saleBreakfast2() {
        synchronized(this){
            if (this.tag) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (this.breakfast > 15) {
                    tag=false;
                    return;
                }
                else{
                    System.out.println(Thread.currentThread().getName()+"在卖早餐---》"+(this.breakfast));
                    this.breakfast++;

                }
            }
        }

    }

}

 

posted @ 2021-11-12 16:00  宇~  阅读(54)  评论(0编辑  收藏  举报