-
学习多线程比较经典的案例就是实现售票系统了。
-
我们先来看看需求:铁道部发布了一个售票任务,要求销售100张票,要求有5个窗口来进行销售,效果如下:
窗口001正在销售第100张票 窗口001正在销售第99张票 窗口002正在销售第98张票 . . . 窗口05正在销售第1张票 票已经销售完毕
-
对需求进行分析:
一共有1000张票,5个窗口同步执行;所以需要用到多线程技术,其中车票数应该被5个窗口共享,不然容易出现出售同一张票的问题。
-
下面用两种实现线程的方式来完成需求:
一、通过继承Thread类
package com.hym.Threaded;
public class SaleSysTest {
public static void main(String[] args) {
//创建5个线程,传入 线程名: [001]、[002]...并开启
for(int i=1;i<6;i++){
new SaleThread("[00"+i+"]").start();
}
}
}
class SaleThread extends Thread {
//车票数被共享,所以定义为static,数量为100.
private static int ticket = 100;
//通过锁来保证线程不会重复访问.
private static Object obj = new Object();
//有参构造传入线程名
public SaleThread(String name) {
super(name);
}
public SaleThread() {
}
//重写run()方法,将售票动作放入其中;
@Override
public void run() {
while (true) {
//在锁外使用sleep( );以便于更好的解决复现问题
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//使用synchronized需要锁统一资源,不然没效果,所以将obj初始化为static静态。
//但让也可以使用字符串 synchronized("lock");lock随便输入
synchronized (obj) {
//还有余票---出票
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "号窗口第"
+ ticket + "票正在出票...");
ticket--;
} else {
//车票售完
System.out.println("车票已售完,下次请趁早...");
//不能使用break或者return,后面进行解释。
System.exit(0);
}
}
}
}
}
- 执行结果:----太长了只截了末尾部分大伙凑合凑合
二、通过实现Runnable接口
- 与第一种方式的区别不大
package com.hym.Threaded;
public class Test {
public static void main(String[] args) {
//得到对象
SaleSys ss = new SaleSys();
//把对象放入线程中
for(int i=1;i<6;i++){
new Thread(ss,"[00"+i+"]").start();
}
}
}
class SaleSys implements Runnable {
//定义票的总数
private int ticket = 100;
//定义一个线程同步对象
private Object obj = new Object();
@Override
public void run() {
while(true){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
//同步锁
synchronized(obj){
if(ticket > 0){
System.out.println(Thread.currentThread().getName()+" 售出第 "+ticket +" 张票");
ticket--;
}else{
System.out.println("票已售完,请下次再来!");
System.exit(0);
}
}
}
}
}
-
执行结果
-
最后解释一下为什么使用System.exit(0)退出,而不是Break,也不是Return。
system.exit(0):是方法调用,在程序的任何地方都会显式表明JVM进程要退出系统了,返回值为0,可以通过%errorlevel%来取得。
return:
它是一个关键字,表明返回调用当前方法的方法中。 如果是在main()方法中,可以起到退出虚拟机就的作用,但是如果是存在多线程的话return并不能保证JVM退出.,因为要所有的线程都结束才行。
当不在main()方法中时,System.exit(0)直接终止程序,就算后面有代码也不执行了,而return则返回至调用该方法的地方,如果后面还有代码则继续执行,Break想必就不用说了吧。
- 在此用return,break的话就会出现 " 下次请趁早+5 " 的情况。当然如果你需要出现每个窗口都提示票售空的情况可以使用break;主要看需求。