使用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方法就是同步方法了。

浙公网安备 33010602011771号