模拟卖票和买票,测试代码是否会出现线程安全问题。
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
@Slf4j
public class 买票卖票 {
public static void main(String[] args) throws InterruptedException {
TicketWindow window = new TicketWindow(1000);
//模拟售票个数
List<Integer> accountList = new Vector<>();
//存取所有线程,用于join
List<Thread> threadList = new ArrayList<>();
for (int i = 0; i < 2000; i++) {
Thread thread = new Thread(() ->{
//售票
int account = window.sell(randomPicket());
//计数
accountList.add(account);
});
threadList.add(thread);
thread.start();
}
for (Thread t : threadList) {
t.join();
}
int all = 0;
for(int i = 0;i < accountList.size();i++){
all += accountList.get(i);
}
log.debug("实际卖出:{}",all);
log.debug("剩余票数:{}",window.getCount());
}
public static int randomPicket(){
return (int)(Math.random() * 10);
}
}
class TicketWindow{
//票的个数
private int count;
public TicketWindow(int count) {
this.count = count;
}
//卖票
public int sell(int num){
if(num < count){
count -= num;
return num;
}else{
return 0;
}
}
public int getCount() {
return count;
}
}
结果展示:
20:05:20.185 [main] DEBUG 买票卖票 - 实际卖出:1007
20:05:20.192 [main] DEBUG 买票卖票 - 剩余票数:1
分析
- 2000个线程共享
window
对象 - 而
window
对象的sell()
方法对count存在读写操作,且sell()方法不具有原子性
解决问题
- 将
sell()
方法使用synchronized
关键字修饰