zoukankan      html  css  js  c++  java
  • java 22

    使用多线程实现的第二种方式:

    首先创建自定义类

     1 public class SellTicket implements Runnable {
     2     // 定义100张票
     3     private int ticket = 100;
     4     
     5     public void run() {
     6         
     7         //假设一直在售票
     8         while(true){
     9         //现实中买票时,都会有延迟的,所以让线程休息下
    10         try {
    11             Thread.sleep(100);
    12         } catch (InterruptedException e) {
    13             e.printStackTrace();
    14         }
    15         if(ticket > 0){
    16             System.out.println(Thread.currentThread().getName()+"正在出售第"+(ticket--)+"张票");
    17         }
    18         19         }
    20     }
    21 }

    创建测试类,售票口设置3个:

     1 public class SellTicket1Demo {
     2 
     3     public static void main(String[] args) {
     4         
     5         // 创建资源对象
     6         SellTicket st = new SellTicket();
     7         
     8         // 创建三个线程对象
     9         Thread st1 = new Thread(st,"售票口1");
    10         Thread st2 = new Thread(st,"售票口2");
    11         Thread st3 = new Thread(st,"售票口3");
    12         
    13         // 启动线程
    14         st1.start();
    15         st2.start();
    16         st3.start();
    17 
    18     }
    19 
    20 }

    当启动程序后,就会发现出现了2个问题:

    第一个问题:会出现2个或者3个售票口同时出售同一张票的情况(售票口1、2、3同时出售第90张票)

    第二个问题:到最后面,甚至售票口在出售第0张、第-1张票

    分析原因:

      第一个问题:会出现2个或者3个售票口同时出售同一张票的情况(售票口1、2、3同时出售第90张票)

    首先我们假设出现了第一个和的第二个售票口同时出售第100张票:

    原因:

      因为线程默认的优先级都是5,一样的,都要抢占资源,这里为了方便解析,设 st1 > st2 。

    我们的理想状况是:st1出售第100张票,st2出售第99张票。

    但是,由于CPU的每一次执行必须是个原子性的操作。

    原子性:最简单基本的操作,比如说i=100,System.out.println(i); 这个就是最简单基本的操作,不能拆分的,而i--就不是了。

    所以,当程序走到

    System.out.println(Thread.currentThread().getName() + "正在出售第"+ (ticket--) + "张票");

    A: CPU会先记录之前的值(这里是ticket=100)

    B: 接着才ticket--

    C: 然后输出原来的值(但是,在CPU执行这个过程时,st2闯进来了)

    D: ticket变成99

    E: st1出售第100张票

    F:由于C步骤时,st2闯进去了。所以st2出售第100张票

    根本原因:CPU的每一次执行必须是个原子性的操作。

    第二个问题:到最后面,甚至售票口在出售第0张、第-1张票

      我们假设最差的情况:窗口1出售第1张票,窗口2出售第0张票,窗口3出售第-1张票:(依旧是假设抢占到资源的顺序是 st1 > st2 > st3)

    原因:

      在走到

    hread.sleep(100); //t1进来了并休息,t2进来了并休息,t3进来了并休息,

    注意:在走到这里的时候,这3个都带着一个变量:ticket = 1; 进来了(具体原因后面说)

    所以,在执行

    System.out.println(Thread.currentThread().getName() + "正在出售第"+ (ticket--) + "张票");

    结果:

      窗口1出售第1张票,ticket = 0;

      窗口2出售第0张票,ticket = -1;

      窗口3出售第-1张票, ticket = -2;  

    当然,这是最差的情况。有可能就窗口2跟进来,也有可能就窗口1进来。

    但是,你不能把期望放在有可能上面。

    根本原因:随机性和延迟

    随机性(这里是不知道几个线程跟着进来)和延迟导致(这里是判断延迟)

    总的说,这两个根本原因其实就是:线程的安全问题。

    线程安全问题在理想状态下,是不容易出现的,但是一旦出现了,对软件的影响非常大。

    所以,我们要解决线程安全问题。

    何事都只需坚持.. 难? 维熟尔。 LZL的自学历程...只需坚持
  • 相关阅读:
    fastjson异常(字符串集合转成字符串数组)
    从url中下载资源(目前测试只有照片,文件类的没有进行测试)
    springboot+mybatisplus进行整合并且使用逆向工程
    maven使用
    maven-相关配置
    【深入】java 单例模式(转)
    jdbcTemplate的配置
    Spring JdbcTemplate 的使用与学习(转)
    spring 第一篇(1-1):让java开发变得更简单(下)转
    context:exclude-filter 与 context:include-filter 转
  • 原文地址:https://www.cnblogs.com/LZL-student/p/5935172.html
Copyright © 2011-2022 走看看