JAVASE学习笔记 实例探索多线程安全问题


临近春节,各大电影院都在筹备准备上映贺岁大片。假设某家电影院持有唐探3的票100张,而且它总共有三个售票窗口,请设计一个程序模拟该电影院进行售票。
在这里插入图片描述


1.利用继承Thread类的方式卖电影票

事件具体分析
1.三个窗口其实就是三个线程
2.定义票的数量为100张(为静态变量,被3个线程所共享
3.创建线程对象,启动线程,每卖一张票,票的数量就减1
public class CellThread extends Thread {
    //定义一个静态常量被3个线程所共享
    static int piao=100;
    @Override
    public void run() {
        while (true) {
            if (piao > 0) {
                System.out.println(this.getName() + "抢到了第" + (piao--) + "票");
            }
        }
    }
}

public class MyTest {
    public static void main(String[] args) {
      /*  A:
        案例演示
        需求:某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。
        通过继承Thread类实现*/
        //100张票 属于共享资源,三个窗口共同卖
        //三个窗口就相当于三个线程。
        CellThread th1 = new CellThread("窗口1");
        CellThread th2 = new CellThread("窗口2");
        CellThread th3 = new CellThread("窗口3");
        th1.start();
        th2.start();
        th3.start();
    }
}

三个线程共享100张票,且抢票是通过线程并发形式去进行的。


2.实现Runnable接口的方式卖电影票

public class CellRunnable implements Runnable {
    //定义公共的静态常量,即为共享变量
    static int piao=100;
    private String name;
    public CellRunnable() {
    }

    @Override
    public void run() {
        while(true){
            if(piao>0)
            System.out.println(Thread.currentThread().getName()+"抢到第"+(piao--)+"张票");
        }
    }
}
public class MyTest2 {
    public static void main(String[] args) {
         /* 需求:某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。
        通过实现Runnable接口实现*/
        //100张票 属于共享资源,三个窗口共同卖
        //三个窗口就相当于三个线程。
        CellRunnable myRunnable= new CellRunnable();
        Thread th1 = new Thread(myRunnable,"窗口1");
        Thread th2 = new Thread(myRunnable,"窗口2");
        Thread th3 = new Thread(myRunnable,"窗口3");

        th1.start();
        th2.start();
        th3.start();
    }
}

3.线程安全问题的实例发生

我们前面已经说过电影院的售票程序,从表面上看不出存在什么问题。但在真实生活中,售票时网络不是实时传输的,总是存在延迟的情况,所以需要一点点时间的延迟。我们可以通过改实现接口的卖票程序,每次延迟100ms,进行模拟网络延迟。设置后买电影票就会发生同票与零票的情况发生。(即发生所谓的线程安全问题)

public class CellRunnable implements Runnable {
    //将票数设置为静态常量,即为共享变量
    static int piao=100;
    @Override
    public void run() {
        while(true){
            try {
                //模拟网络演延迟
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(piao>0){
                System.out.println(Thread.currentThread().getName()+"抢到了第"+(piao--)+"张票");
            }
        }

public class MyTest {
    public static void main(String[] args) {
        /*
         *  我们模拟了一下,网络售票延迟,就出现了一些不合理的数据,也就是说,出现了线程安全问题。
         * 1.出现了0票 同票,这是由于线程的随机性导致,并发导致的。
         * 2.出现了重复票,原因是由于,原子性所导致的,原子性:不可再分割性
         *   piao-- 它不是一个原子性的操作。
         * piao-- 要经过三个步骤 读 改  写
         * */
        CellRunnable cellRunnable = new CellRunnable();
        Thread th1 = new Thread(cellRunnable,"窗口1");
        Thread th2 = new Thread(cellRunnable,"窗口2");
        Thread th3 = new Thread(cellRunnable, "窗口3");

        th1.start();
        th2.start();
        th3.start();
    }
}

出现了同票、零票与负票的现象:

在这里插入图片描述


4.分析多线程安全问题的产生原因

通常判断一个多线程应用程序是否有问题的标准:

  • 1.是否是多线程环境
  • 2.是否存在共享数据
  • 3.是否存在多条语句同时操作共享数据
    上面的卖票程序是存在问题的,因为它满足上面的标准,才会引起多线程的安全问题。那么我们就可以解决这个问题,而上面的标准中是否存在多线程环境与是否存在共享数据是不能打乱的。因此我们对是否存在多条语句同时操作共享数据可以进行处理。

处理的思路为:我们将操作共享数据的多条语句看作成一个整体,当一个线程执行这个整体时,其他的线程处于等待的状态,也就是说当一个线程执行这个整体的时候,其他线程不能执行。

总结

对于线程的安全性的实例以及产生原因已经介绍给大家了,下次给大家介绍具体解决线程安全问题的方案。
在这里插入图片描述

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页