11、多執行緒視窗銷售火車票之初體驗
前面的博文中記錄了一些關於多執行緒比較基礎的一些API知識,本篇博文將在此基礎上,整一個簡單的模擬火車票銷售的場景。此文只是簡單的模擬,後續會對此進行改進!
package com.demo10; public class Tickets extends Thread{ private int lastTickets = 50; @Override public void run() { while (true) { if(lastTickets > 0){ lastTickets--; System.out.println(Thread.currentThread().getName() + "賣出一張,餘票:" + lastTickets + "張"); }else{ System.out.println("票已經賣完了!"); Thread.currentThread().stop(); } } } }
package com.demo10; public class Run { public static void main(String[] args) { Tickets tickets = new Tickets(); Thread t1 = new Thread(tickets,"視窗A"); Thread t2 = new Thread(tickets,"視窗B"); Thread t3 = new Thread(tickets,"視窗C"); t1.start(); t2.start(); t3.start(); } }
輸出結果:
視窗A賣出一張,餘票:49張 視窗A賣出一張,餘票:48張 視窗A賣出一張,餘票:47張 視窗A賣出一張,餘票:46張 視窗A賣出一張,餘票:45張 視窗A賣出一張,餘票:44張 視窗A賣出一張,餘票:43張 視窗A賣出一張,餘票:42張 視窗A賣出一張,餘票:41張 視窗A賣出一張,餘票:40張 視窗A賣出一張,餘票:39張 視窗A賣出一張,餘票:38張 視窗A賣出一張,餘票:37張 視窗A賣出一張,餘票:36張 視窗A賣出一張,餘票:35張 視窗A賣出一張,餘票:34張 視窗B賣出一張,餘票:33張 視窗A賣出一張,餘票:32張 視窗B賣出一張,餘票:31張 視窗A賣出一張,餘票:30張 視窗B賣出一張,餘票:29張 視窗A賣出一張,餘票:27張 視窗C賣出一張,餘票:27張 視窗A賣出一張,餘票:25張 視窗B賣出一張,餘票:26張 視窗A賣出一張,餘票:23張 視窗C賣出一張,餘票:24張 視窗A賣出一張,餘票:21張 視窗B賣出一張,餘票:22張 視窗A賣出一張,餘票:19張 視窗C賣出一張,餘票:20張 視窗A賣出一張,餘票:17張 視窗B賣出一張,餘票:18張 視窗A賣出一張,餘票:15張 視窗C賣出一張,餘票:16張 視窗A賣出一張,餘票:13張 視窗B賣出一張,餘票:14張 視窗A賣出一張,餘票:11張 視窗C賣出一張,餘票:12張 視窗A賣出一張,餘票:9張 視窗B賣出一張,餘票:10張 視窗A賣出一張,餘票:7張 視窗C賣出一張,餘票:8張 視窗A賣出一張,餘票:5張 視窗B賣出一張,餘票:6張 視窗A賣出一張,餘票:3張 視窗C賣出一張,餘票:4張 視窗A賣出一張,餘票:1張 視窗B賣出一張,餘票:2張 票已經賣完了! 票已經賣完了! 視窗C賣出一張,餘票:0張 票已經賣完了!
從輸出結果來看啊,三個賣票視窗(執行緒)啟動之後,都在各賣各的,也不知道自己賣的票號是不是已經被其他視窗賣出去了,產生了多個視窗賣同一張票的錯誤。這是對消費者的一種欺騙啊。為了防止類似的事情發生,我們必須採取強烈的措施來對賣票視窗進行管理。目前採用的是加同步鎖。意思就是 每一張票(資源)都是公平的擺在那裡供三個視窗銷售,但是隻要某一個視窗搶先拿到了銷售火車票(資源)的機會,就會把資源(火車票)鎖住(加鎖),讓其他視窗(執行緒)無法對該資源進行操作,這樣就不會出現亂套的現象了。只是加鎖 ,使用完畢釋放鎖,對效能好像有一定的影響,後面線上程的高階階段再來探討。
對票採取同步操作 鎖住this物件
package com.demo10;
public class Tickets extends Thread{
private int lastTickets = 50;
@Override
public void run() {
while (true) {
synchronized (this){
if(lastTickets > 0){
lastTickets--;
System.out.println(Thread.currentThread().getName() +
"賣出一張,餘票:" + lastTickets + "張");
}else{
System.out.println("票已經賣完了!");
Thread.currentThread().stop();
}
}
}
}
}
執行結果:
視窗A賣出一張,餘票:49張
視窗A賣出一張,餘票:48張
視窗A賣出一張,餘票:47張
視窗A賣出一張,餘票:46張
視窗A賣出一張,餘票:45張
視窗A賣出一張,餘票:44張
視窗A賣出一張,餘票:43張
視窗A賣出一張,餘票:42張
視窗A賣出一張,餘票:41張
視窗A賣出一張,餘票:40張
視窗A賣出一張,餘票:39張
視窗A賣出一張,餘票:38張
視窗A賣出一張,餘票:37張
視窗A賣出一張,餘票:36張
視窗A賣出一張,餘票:35張
視窗A賣出一張,餘票:34張
視窗A賣出一張,餘票:33張
視窗A賣出一張,餘票:32張
視窗A賣出一張,餘票:31張
視窗A賣出一張,餘票:30張
視窗A賣出一張,餘票:29張
視窗A賣出一張,餘票:28張
視窗A賣出一張,餘票:27張
視窗A賣出一張,餘票:26張
視窗A賣出一張,餘票:25張
視窗A賣出一張,餘票:24張
視窗A賣出一張,餘票:23張
視窗A賣出一張,餘票:22張
視窗A賣出一張,餘票:21張
視窗A賣出一張,餘票:20張
視窗A賣出一張,餘票:19張
視窗A賣出一張,餘票:18張
視窗A賣出一張,餘票:17張
視窗A賣出一張,餘票:16張
視窗A賣出一張,餘票:15張
視窗A賣出一張,餘票:14張
視窗A賣出一張,餘票:13張
視窗A賣出一張,餘票:12張
視窗A賣出一張,餘票:11張
視窗A賣出一張,餘票:10張
視窗A賣出一張,餘票:9張
視窗A賣出一張,餘票:8張
視窗A賣出一張,餘票:7張
視窗A賣出一張,餘票:6張
視窗A賣出一張,餘票:5張
視窗A賣出一張,餘票:4張
視窗A賣出一張,餘票:3張
視窗A賣出一張,餘票:2張
視窗A賣出一張,餘票:1張
視窗A賣出一張,餘票:0張
票已經賣完了!
票已經賣完了!
票已經賣完了!
對票採取同步操作 鎖住方法
package com.demo10;
public class Tickets extends Thread{
private int lastTickets = 50;
@Override
public void run() {
while (true) {
sale();
}
}
synchronized public void sale(){
if(lastTickets > 0){
lastTickets--;
System.out.println(Thread.currentThread().getName() +
"賣出一張,餘票:" + lastTickets + "張");
}else{
System.out.println("票已經賣完了!");
Thread.currentThread().stop();
}
}
}
執行結果:
視窗A賣出一張,餘票:49張
視窗A賣出一張,餘票:48張
視窗B賣出一張,餘票:47張
視窗B賣出一張,餘票:46張
視窗B賣出一張,餘票:45張
視窗B賣出一張,餘票:44張
視窗B賣出一張,餘票:43張
視窗B賣出一張,餘票:42張
視窗B賣出一張,餘票:41張
視窗B賣出一張,餘票:40張
視窗B賣出一張,餘票:39張
視窗B賣出一張,餘票:38張
視窗B賣出一張,餘票:37張
視窗C賣出一張,餘票:36張
視窗C賣出一張,餘票:35張
視窗C賣出一張,餘票:34張
視窗C賣出一張,餘票:33張
視窗C賣出一張,餘票:32張
視窗C賣出一張,餘票:31張
視窗C賣出一張,餘票:30張
視窗C賣出一張,餘票:29張
視窗C賣出一張,餘票:28張
視窗C賣出一張,餘票:27張
視窗C賣出一張,餘票:26張
視窗C賣出一張,餘票:25張
視窗C賣出一張,餘票:24張
視窗C賣出一張,餘票:23張
視窗C賣出一張,餘票:22張
視窗C賣出一張,餘票:21張
視窗C賣出一張,餘票:20張
視窗C賣出一張,餘票:19張
視窗C賣出一張,餘票:18張
視窗C賣出一張,餘票:17張
視窗C賣出一張,餘票:16張
視窗C賣出一張,餘票:15張
視窗C賣出一張,餘票:14張
視窗C賣出一張,餘票:13張
視窗C賣出一張,餘票:12張
視窗C賣出一張,餘票:11張
視窗C賣出一張,餘票:10張
視窗C賣出一張,餘票:9張
視窗C賣出一張,餘票:8張
視窗C賣出一張,餘票:7張
視窗C賣出一張,餘票:6張
視窗C賣出一張,餘票:5張
視窗C賣出一張,餘票:4張
視窗C賣出一張,餘票:3張
視窗C賣出一張,餘票:2張
視窗C賣出一張,餘票:1張
視窗C賣出一張,餘票:0張
票已經賣完了!
票已經賣完了!
票已經賣完了!