很久没有更新过了,见到阅读量有所上涨,是时候水一篇文章了!
正好前两天有人问到这个多线程卖票的案例,干脆把这个写一下!争取最简单的问题讲的通透!
并发讲究的就是:原子性、一致性、有序性!
根据这三点,可以分析,票数是一个共享变量,所以无论多少人售卖,到了加减操作的时候,都必须使得这个操作是一个有序的串行的!原子性放在这里那自然是查票和减票时候是作为一个事务来处理!
所以,分析完了,下面是一个使用synchronized加锁方式,使得多个售票线程共用一个锁,这样保证票数在同一时间,只能由一个线程进行操作!
package com.maple.m2;
public class _11_TicketTest {
public static void main(String[] args) {
_11_T t = new _11_T();
_11_SaleThread threadA = new _11_SaleThread(t);
_11_SaleThread threadB = new _11_SaleThread(t);
_11_SaleThread threadC = new _11_SaleThread(t);
_11_SaleThread threadD = new _11_SaleThread(t);
threadA.start();
threadB.start();
threadC.start();
threadD.start();
}
}
/**
* 里面的两个方法略显多余,只是为了好看!
*/
class _11_T {
private Integer count = 10;
public Integer getCount() {
return count;
}
public void sale() {
this.count--;
}
}
class _11_SaleThread extends Thread {
private _11_T t;
public _11_SaleThread(_11_T t) {
this.t = t;
}
@Override
public void run() {
while (true) {
// 模拟业务处理时间
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 这里使用别的作为锁也是可以的,只要保证多个线程共同使用同一个锁即可!
synchronized (t) {
Integer count = t.getCount();
if (count > 0) {
t.sale();
System.out.println(Thread.currentThread().getName() + " 出票前剩余 -> " + count + "\t出票后剩余 -> " + (count - 1));
} else {
System.out.println(Thread.currentThread().getName() + " ---> 空");
break;
}
}
}
}
}
实现方法是多种多样的,这只是诸多方法中的一个,也并不是最好的写法!只要理解了锁,这个可以说就很简单了!
下面附实验图: