zoukankan      html  css  js  c++  java
  • JAVA学习之路(多线程)---模拟售票(细解)

    首先看题目描述:

    假设有火车票100张,创建4个线程模拟4个售票点,每100ms售出一张,打印出售票过程,格式如下:

    窗口3:卖出第100张票

    窗口4:卖出第99张票 

    ............

    ............

    简单的思路就是创建一个类,首先肯定要去继承Thread。开启线程,由于是4个窗口,肯定要开启4个线程。然后让每个线程去输出结果,也就是卖出去的票。这里很多人想不到如何让4个线程不打印重复的票。(比如4个线程都卖出去了第100张票,这显然是不合理的)。

    看代码:

      

     1 package com.lesson.thread;
     2 
     3 public class MyThread {
     4 
     5     public static void main(String[] args) {
     6         Ticket sell1 = new Ticket();
     7         Ticket sell2 = new Ticket();
     8         Ticket sell3 = new Ticket();
     9         Ticket sell4 = new Ticket();
    10         sell1.setName("窗口1");
    11         sell2.setName("窗口2");
    12         sell3.setName("窗口3");
    13         sell4.setName("窗口4");
    14         sell1.start();
    15         sell2.start();
    16         sell3.start();
    17         sell4.start();
    18     }
    19 }
    20 class Ticket extends Thread {
    21     private static int tickets = 100;//这里设置成static,目的是让每个线程共享这个变量。以免出现重复打印的现象。
    22     @Override
    23     public void run() {
    24         while(true) {
    25             if(tickets <= 0) {
    26                 break;
    27             }
    2829          System.out.println(getName()+":买出第"+tickets--+"张票。");//卖出一张减一张票
    30 31         }
    32     }
    33     
    34 }

    可能你已经看到了你想要的结果了。但是,还没完。目前代码写到这里是有问题的!!!

    为什么?

    看下面的代码:

    package thread;
    public class Mythread {
    
        public static void main(String[] args) {
            Ticket sell1 = new Ticket();
            Ticket sell2 = new Ticket();
            Ticket sell3 = new Ticket();
            Ticket sell4 = new Ticket();
            sell1.setName("窗口1");
            sell2.setName("窗口2");
            sell3.setName("窗口3");
            sell4.setName("窗口4");
            sell1.start();
            sell2.start();
            sell3.start();
            sell4.start();
        }
    }
    class Ticket extends Thread {
        private static int tickets = 100;
        @Override
        public void run() {
            while(true) {
                if(tickets <= 0) {
                    break;
                }
                try {
                    Thread.sleep(10);          //让进来的线程睡10ms;线程1,2,3,4都睡在这
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(getName()+":买出了第"+tickets--+"张票。");
            }
        }    
    }

    与开始的代码不同在于让进来的线程睡一会。可以看到如下运行结果:

    窗口2:买出了第0张票。
    窗口3:买出了第-1张票。
    窗口1:买出了第-2张票

    这里编者调出来了出问题的地方。可以看到怎么会第0,-1,-2张票???

    做出解释:

    其实在这里让线程睡一会就是为了演示这里有很多行代码要执行。假设票已经卖到第1张了,也就是tickets=1,然后第一条线程进来判断 tickets <= 0 ?不成立,然后线程1要睡 10ms,紧接着,线程2进来,这时 tickets 还是为1,因为线程1在睡,tickets 没有减 。然后线程2判断 tickets <= 0 ? 还是不成立,线程2又开始睡。同样,线程3,线程4都睡了。 这时的tickets 还是等于1的。然后线程1先醒过来,开始输出结果,tickets 减了1。可是这是其他的线程还是经过while里面的判断语句进来了的,只是睡了。所以当其他线程醒过来的时候,还是会打印出结果的。也就出现了上面的问题。

    解决方法:

     多线程并发改变同一变量,为了解决,采用同步代码块synchronized。里面加任意的对象,但是不能加this,因为这里创建了四个线程,每一个线程都有自己的对象,所以是四个不同的对象,没有用。所以这里不能用this,必须锁在同一个对象里才行。而Thickets.class这是唯一的。

    package thread;
    public class Mythread {
    
        public static void main(String[] args) {
            Ticket sell1 = new Ticket();
            Ticket sell2 = new Ticket();
            Ticket sell3 = new Ticket();
            Ticket sell4 = new Ticket();
            sell1.setName("窗口1");
            sell2.setName("窗口2");
            sell3.setName("窗口3");
            sell4.setName("窗口4");
            sell1.start();
            sell2.start();
            sell3.start();
            sell4.start();
        }
    }
    class Ticket extends Thread {
        private static int tickets = 100;
        @Override
        public void run() {
            while(true) {
                synchronized (Ticket.class) {//同步代码块
                    if(tickets <= 0) {
                        break;
                    }
                    try {
                        Thread.sleep(100);          //每100ms卖出一张
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName()+":买出了第"+tickets--+"张票。");
                }
            }
        }    
    }
  • 相关阅读:
    CSS3 animation 属性
    关于shortcut icon和icon代码的区别介绍
    用js判断一个复选框是否被选中
    今天开始,走不一样的路
    JavaScript 中的对象
    (已转)Linux基础第七章 线程
    (已转)C++知识图谱
    Linux基础 文件和目录
    (已转)Linux基础第六章 信号
    Linux第四章 进程
  • 原文地址:https://www.cnblogs.com/HoweZhan/p/10185166.html
Copyright © 2011-2022 走看看