zoukankan      html  css  js  c++  java
  • Android-Java卖票案例-推荐此方式Runnable

    上一篇博客 Android-卖票案例static-不推荐此方式,讲解了卖票案例是 private static int ticket = 10;,static静态的这种方式来解决卖票多卖30张的问题,但并不推荐这种方式,因为还有更加合理的方式,那就不得不提到Runnable接口,此篇博客就是使用Runnable来解决卖票多卖30张的问题


    需求描述:四个窗口一起卖票,把10张票卖完,不许多卖

    先看一个错误的案例:

    package android.java.thread06;
    
    /**
     * 售票线程
     */
    class Booking extends Thread {
    
        /**
         * 模拟票的总算 10张票
         */
        private int ticket = 10;
    
        @Override
        public void run() {
            super.run();
    
            while (ticket > 0) {
                System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
                ticket -- ;
            }
        }
    }
    
    /**
     * 售票案例
     */
    public class BookingTest {
    
        public static void main(String[] args) {
    
            // 实例化线程对象
            Thread thread1 = new Booking();
            Thread thread2 = new Booking();
            Thread thread3 = new Booking();
            Thread thread4 = new Booking();
    
            // 开启启动线程
            thread1.start(); // 启动第Thread-0窗口 执行卖票任务
            thread2.start(); // 启动第Thread-1窗口 执行卖票任务
            thread3.start(); // 启动第Thread-2窗口 执行卖票任务
            thread4.start(); // 启动第Thread-3窗口 执行卖票任务
        }
    
    }

    日志结果:

    名称:Thread-0窗口卖出第10张票
    名称:Thread-0窗口卖出第9张票
    名称:Thread-0窗口卖出第8张票
    名称:Thread-1窗口卖出第10张票
    名称:Thread-0窗口卖出第7张票
    名称:Thread-0窗口卖出第6张票
    名称:Thread-0窗口卖出第5张票
    名称:Thread-0窗口卖出第4张票
    名称:Thread-0窗口卖出第3张票
    名称:Thread-0窗口卖出第2张票
    名称:Thread-0窗口卖出第1张票
    名称:Thread-1窗口卖出第9张票
    名称:Thread-1窗口卖出第8张票
    名称:Thread-1窗口卖出第7张票
    名称:Thread-1窗口卖出第6张票
    名称:Thread-1窗口卖出第5张票
    名称:Thread-1窗口卖出第4张票
    名称:Thread-1窗口卖出第3张票
    名称:Thread-1窗口卖出第2张票
    名称:Thread-2窗口卖出第10张票
    名称:Thread-2窗口卖出第9张票
    名称:Thread-1窗口卖出第1张票
    名称:Thread-2窗口卖出第8张票
    名称:Thread-2窗口卖出第7张票
    名称:Thread-3窗口卖出第10张票
    名称:Thread-3窗口卖出第9张票
    名称:Thread-2窗口卖出第6张票
    名称:Thread-3窗口卖出第8张票
    名称:Thread-3窗口卖出第7张票
    名称:Thread-2窗口卖出第5张票
    名称:Thread-3窗口卖出第6张票
    名称:Thread-2窗口卖出第4张票
    名称:Thread-3窗口卖出第5张票
    名称:Thread-2窗口卖出第3张票
    名称:Thread-3窗口卖出第4张票
    名称:Thread-2窗口卖出第2张票
    名称:Thread-2窗口卖出第1张票
    名称:Thread-3窗口卖出第3张票
    名称:Thread-3窗口卖出第2张票
    名称:Thread-3窗口卖出第1张票

    从日志结果来看,没有实现需求,反而多卖了30张,例如:本来一节车厢坐10人,结果一节车厢卖了40张票,这是非常严重的错误

    为什么会这样呢,看内存图就明白了:

    由于 Thread-0线程有自己的ticket变量 

       Thread-1线程有自己的ticket变量 

       Thread-2线程有自己的ticket变量 

       Thread-3线程有自己的ticket变量  

         所以才会造成40张票 


    在main方法中,thread1.start();/thread2.start();/thread3.start();/thread4.start();  四个线程去启动一个Runnable实现类Booking,ticket变量就是只有一个

    package android.java.thread07;
    
    /**
     * 售票线程
     */
    class Booking implements Runnable {
    
        /**
         * 模拟票的总算 10张票
         */
        private int ticket = 10;
    
        @Override
        public void run() {
    
            while (ticket > 0) {
    
                if (ticket > 0) {
                    System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
                    ticket--;
                }
            }
    
        }
    }
    
    /**
     * 售票案例
     */
    public class BookingTest {
    
        public static void main(String[] args) {
    
            /**
             * 定义Runnable实现类Booking,此实现类Booking不是线程,此实现类Booking给四个Thread去执行的
             */
            Runnable booking = new Booking();
    
            // 实例化线程对象
            Thread thread1 = new Thread(booking); // 此实现类Booking给Thread去执行的
            Thread thread2 = new Thread(booking); // 此实现类Booking给Thread去执行的
            Thread thread3 = new Thread(booking); // 此实现类Booking给Thread去执行的
            Thread thread4 = new Thread(booking); // 此实现类Booking给Thread去执行的
    
            // 开启启动线程
            thread1.start(); // 启动第Thread-0窗口 执行卖票任务
            thread2.start(); // 启动第Thread-1窗口 执行卖票任务
            thread3.start(); // 启动第Thread-2窗口 执行卖票任务
            thread4.start(); // 启动第Thread-3窗口 执行卖票任务
        }
    
    }

    结果出现相同的票,这是CPU非常非常快速切换随机性造成的: 

    结果只出现了 Thread-0  和 Thread-1 那是因为 Thread-0 已经把ticket-- 到 0了,所以无法其他的线程对象无法进入while循环,也就无法看到打印

     


    解决CPU快速切换四个线程,导致重复卖票的问题,加同步synchronized

    package android.java.thread07;
    
    /**
     * 售票线程
     */
    class Booking implements Runnable {
    
        /**
         * 模拟票的总算 10张票
         */
        private int ticket = 10;
    
        @Override
        public void run() {
    
            while (ticket > 0) {
    
                /**
                 * 加入同步标识,进行拦截,例如:我在ticket-- =9 的时候 其他线程不准ticket-- =9,这样就解决了重复--值的问题
                 */
                synchronized (Booking.class) {
                    /**
                     * 必须在同步里面再次判断 ticket > 0 , 因为CUP对四个线程切换太快 有可能ticket=-1 或 ticket=-2 ... ,所以必须再次判断
                     */
                    if (ticket > 0) {
                        System.out.println("名称:" + Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
                        ticket--;
                    }
                }
            }
    
        }
    }
    
    /**
     * 售票案例
     */
    public class BookingTest {
    
        public static void main(String[] args) {
    
            /**
             * 定义Runnable实现类Booking,此实现类Booking不是线程,此实现类Booking给四个Thread去执行的
             */
            Runnable booking = new Booking();
    
            // 实例化线程对象
            Thread thread1 = new Thread(booking); // 此实现类Booking给Thread去执行的
            Thread thread2 = new Thread(booking); // 此实现类Booking给Thread去执行的
            Thread thread3 = new Thread(booking); // 此实现类Booking给Thread去执行的
            Thread thread4 = new Thread(booking); // 此实现类Booking给Thread去执行的
    
            // 开启启动线程
            thread1.start(); // 启动第Thread-0窗口 执行卖票任务
            thread2.start(); // 启动第Thread-1窗口 执行卖票任务
            thread3.start(); // 启动第Thread-2窗口 执行卖票任务
            thread4.start(); // 启动第Thread-3窗口 执行卖票任务
        }
    
    }

    执行结果:已经满足需求

     

  • 相关阅读:
    C++_标准模板库STL概念介绍2-泛型编程
    C++_标准模板库STL概念介绍1-建立感性认知
    C++_新特性1-类型转换运算符
    C++_新特性2-RTTI运行阶段类型识别
    C++_异常9-异常的注意事项
    C++_异常8-异常、类和基础
    C++_异常7-exception类
    C++_异常6-其他异常特性
    redis数据类型之—List
    redis数据类型之—Hash
  • 原文地址:https://www.cnblogs.com/android-deli/p/10226347.html
Copyright © 2011-2022 走看看