多线程售票程序
场景介绍
现实生活中,火车站售票厅都是多个窗口同时售票的,同一张票只能被一位乘客所买,当然我们可以去任意一个窗口买票,所以这些票是这些窗口的共享资源,需要对共享的资源进行处理否则就会出现一张票被多个人持有的现象这当然是不允许的。本程序就是模拟多线程售票案例,以同步方式来处理资源共享导致的线程安全问题。
通过继承Thread类来实现
TicketThread Code
/**
* @author xuyi3
* @2016年4月7日 @上午11:46:41
* @ThreadTicket
* @功能说明:通过继承Thread来实现多线程售票<br>
* @春风十里不如你
* @备注
*/
public class ThreadTicket extends Thread {
// 如果是继承Thread类的话,多线程只能通过使用静态变量来共享资源了,否则每个线程都有自己一份资源,不存在共享资源一说。
private static int tickets = 100;// 总工一百张票
//注意使用的是static final 修饰符
private static final Object obj = new Object();
// 给予售票线程一个自定义名字
public ThreadTicket(String name) {
setName(name);
}
@Override
public void run() {
while (true) {
synchronized (ThreadTicket.class) {// 使用obj也可以,但是注意obj是static final
// 即单例的不变的。
if (tickets > 0) {
System.out.println(
Thread.currentThread().getName() + "售票" + tickets);
tickets--;
}
}
}
}
}
AppMain Code
public class AppMain {
public static void main(String[] args) {
// 四个售票线程
ThreadTicket threadTicket1 = new ThreadTicket("售票员【1】");
ThreadTicket threadTicket2 = new ThreadTicket("售票员【2】");
ThreadTicket threadTicket3 = new ThreadTicket("售票员【3】");
ThreadTicket threadTicket4 = new ThreadTicket("售票员【4】");
// 启动四个售票线程
threadTicket1.start();
threadTicket2.start();
threadTicket3.start();
threadTicket4.start();
}
}
备注:使用继承Thread方式,是存在弊端的。因为使用了static修饰符(内存加载变大,风险更大)
通过实现Runnable接口来实现
RunnableTicket Code
/**
* @author xuyi3
* @2016年4月7日 @下午1:18:02
* @RunnableTicket
* @功能说明:通过实现Runnable接口来实现多线程售票<br>
* @春风十里不如你
* @备注
*/
public class RunnableTicket implements Runnable {
// 共享资源总票数100张
private int tickets = 100;// 通过使用实现Runnable接口就可以让多个线程共享其中的普通成员变量,而不是每个线程都有一份引用
@Override
public void run() {
while (true) {
synchronized (this) {//注意这里同步的是this对象,值得思考
if (tickets > 0) {
System.out.println(
Thread.currentThread().getName() + "售票" + tickets);
tickets--;
}
}
}
}
}
AppMain Code
public class AppMain {
public static void main(String[] args) {
// 创建一个Runnable对象(注意是一个对象而不是多个对象)
RunnableTicket runnableTicket = new RunnableTicket();
// 启动四个线程售票
new Thread(runnableTicket, "售票员【1】").start();
new Thread(runnableTicket, "售票员【2】").start();
new Thread(runnableTicket, "售票员【3】").start();
new Thread(runnableTicket, "售票员【4】").start();
}
}
总结说明:
虽然使用继承Thread和实现Runnable接口都可以达到模拟多线程售票案例,但是明显实现Runnbale接口方式更优雅和方便扩展,并且无需使用静态变量达到共享目的。
同步的两个前提:
1、多线程环境
2、资源共享(同一个对象的锁)