使用Runnable实现售票机自动贩卖功能

我们假设某个游乐园入口有四个售票点,一共有200张票,四个售票点同时售票。那么在代码中如何实现这个功能?

我们可以先创建一个TicketThread类:

TicketThread.java:

 1 package com.hw.third0225;
 2 
 3 public class TicketThread implements Runnable{
 4     
 5     private int ticket = 1;
 6     
 7     @Override
 8     public void run() {
 9         while(true)
10         {
11             
12             if(ticket < 201){
13                 System.out.println(Thread.currentThread().getName()+"售卖出了"+ticket+"张票");
14                 ticket++;
15             }else{
16                 break;
17             }
18         }
19     }
20 }

然后再创建一个SellingTickets类:

 1 package com.hw.third0225;
 2 
 3 public class SellingTickets {
 4     public static void main(String[] args) {
 5         TicketThread th = new TicketThread();
 6         
 7         Thread t1 = new Thread(th,"1号售票机");
 8         t1.start();
 9         
10         Thread t2 = new Thread(th,"2号售票机");
11         t2.start();
12         
13         Thread t3 = new Thread(th,"3号售票机");
14         t3.start();
15         
16         Thread t4 = new Thread(th,"4号售票机");
17         t4.start();
18     }
19 }

这样就好了,然后我们来运行一下:

 

 你会惊奇地发现,为什么1、2、4号售票机都售卖了第1张票?


 

线程的安全问题:

其实这里涉及到线程的安全问题。什么意思?就是说,假如我有t1,t2两个售票机,那么在TicketThread.java中,我t1抢到了CPU,还没运行到ticket++这一步,CPU就被t2抢走了。因为咱们的CPU是会给线程们分配时间片的嘛。所以这种可能是肯定存在的。怎么解决呢?

我们可以给核心代码加个锁:

TicketThread.java:

 1 package com.hw.third0225;
 2 
 3 import java.util.Random;
 4 
 5 public class TicketThread implements Runnable{
 6     
 7     private int ticket = 1;
 8     private Object lock = new Object();
 9     
10     @Override
11     public void run() {
12         while(true)
13         {
14             synchronized (lock) {
15                 if(ticket < 201){
16                     System.out.println(Thread.currentThread().getName()+"售卖出了"+ticket+"张票");
17                     ticket++;
18                 }else{
19                     break;
20                 }
21             }
22             Random rand = new Random();
23             try {
24                 Thread.sleep(rand.nextInt(20));
25             } catch (InterruptedException e) {
26                 // TODO Auto-generated catch block
27                 e.printStackTrace();
28             }
29         }
30     }
31 }

这样一来,我t1抢走了CPU,并抢走了钥匙,当t2过来抢的时候发现钥匙被带走了,那也就没办法抢走CPU了。然后,我们还需要把这个钥匙lock设置为私有变量,这样四个售票机共享一把钥匙,否则这样做没有任何效果。然后,在某一台售票机运行完后,我让程序休眠一会儿,再来让他们四个一起抢,就会比较均匀。 注意一点,这个锁一般我们设置为Object类型的。

这里其实也可使用同步方法,来看代码:

 

 1 package com.hw.third0225;
 2 
 3 import java.util.Random;
 4 
 5 public class TicketThread implements Runnable{
 6     
 7     private int ticket = 1;
 8     private Object lock = new Object();
 9     
10     @Override
11     public void run() {
12         while(ticket < 201)
13         {
14             sellingTickets();
15             Random rand = new Random();
16             try {
17                 Thread.sleep(rand.nextInt(20));
18             } catch (InterruptedException e) {
19                 // TODO Auto-generated catch block
20                 e.printStackTrace();
21             }
22         }
23     }
24     
25     public synchronized void sellingTickets(){
26         if(ticket < 201){
27             System.out.println(Thread.currentThread().getName()+"售卖出了"+ticket+"张票");
28             ticket++;
29         }
30     }
31 }

 

synchronized的对象默认为当前对象。sellingTickets方法就是同步方法了。

 

posted @ 2021-02-25 12:28  EvanTheBoy  阅读(107)  评论(0)    收藏  举报