老生常談之多線程賣票問題


代碼系本人逐字逐句編寫所得,轉載請注明出處,謝謝合作!

   多線程售票的問題算是老生常談了,筆者是Java初學者,曾為弄清楚這個問題在度娘里搜過好多篇關於這個問題的代碼,發現正確的代碼還是很有限.
粘貼復制的現象很嚴重,而且大多數代碼問題主要是在打印車票超過數量的問題上(部分會打印出負數票號),還有個別會出現表面看似打印結果正確,但其實程序中還有線程在等待執行(在Eclipse的控制台看到明顯的"紅點"一直在亮着).以下是筆者自己寫的關於這個問題的代碼,由於個人水平有限,難免有所疏漏,希望大家莫吝賜教!

源代碼:

 1 import java.text.NumberFormat;
 2 
 3 public class SellTickets {
 4     public static void main(String[] args) {
 5 
 6         //創建車票對象,並初始化車票總數
 7         Ticket ticket=new Ticket(1000);
 8         
 9         //創建售票線程 ,並設置窗口名字,然后啟動線程,這里設置四個窗口
10         new Thread(ticket,"窗口A").start();
11         new Thread(ticket,"窗口B").start();
12         new Thread(ticket,"窗口C").start();
13         new Thread(ticket,"窗口D").start();
14         
15     }
16 }
17 
18 /**
19  * 采用實現Runnable接口的方式實現多線程
20  */
21 class Ticket implements Runnable {
22 
23     //總的車票數
24     int total;
25     
26     Ticket(int total){
27         this.total=total;
28     }
29     
30     //初始車票號碼 1
31     int num = 1;
32 
33     @Override
34     public void run() {
35         while (true) {
36 
37             synchronized ("") {
38                 try {
39                     // 任何線程獲取"線程鎖"以后都要先判斷是否還有余票,防止等待的線程多打印車票
40                     if (num > total)            return;
41                     
42                     // 獲取當前線程名字
43                     String threadName = Thread.currentThread().getName();
44                     
45                     // 格式化票號
46                     String ticketNum = FormatTicketNum(num++);
47                     
48                     // 打印火車票,休眠20毫秒模擬打印車票時間
49                     Thread.sleep(20);
50                     System.out.println(threadName + " 售出火車票No." + ticketNum);
51                     
52                     // 某線程售完最后一張車票時,放出"車票已售罄"提示
53                     if (num > total) {
54                         System.out.println("車票已售罄!");
55                         return;
56                     }
57                 } catch (InterruptedException e) {
58                     e.printStackTrace();
59                 }
60             }
61         }
62     }
63 
64     /**
65      * 格式化車票號碼
66      */
67     static String FormatTicketNum(int num) {
68 
69         NumberFormat nf = NumberFormat.getIntegerInstance();
70         nf.setMinimumIntegerDigits(3);
71         return nf.format(num);
72     }
73 }

打印結果:

 1 窗口D 售出火車票No.001
 2 窗口D 售出火車票No.002
 3 窗口D 售出火車票No.003
 4 窗口D 售出火車票No.004
 5 窗口D 售出火車票No.005
 6 窗口D 售出火車票No.006
 7 窗口D 售出火車票No.007
 8 窗口D 售出火車票No.008
 9 窗口D 售出火車票No.009
10 窗口D 售出火車票No.010
11 窗口D 售出火車票No.011
12 窗口D 售出火車票No.012
13 窗口D 售出火車票No.013
14 窗口D 售出火車票No.014
15 窗口D 售出火車票No.015
16 窗口D 售出火車票No.016
17 窗口D 售出火車票No.017
18 窗口D 售出火車票No.018
19 窗口D 售出火車票No.019
20 窗口D 售出火車票No.020
21 窗口D 售出火車票No.021
22 窗口D 售出火車票No.022
23 窗口D 售出火車票No.023
24 窗口D 售出火車票No.024
25 窗口D 售出火車票No.025
26 窗口D 售出火車票No.026
27 窗口D 售出火車票No.027
28 窗口D 售出火車票No.028
29 窗口D 售出火車票No.029
30 窗口D 售出火車票No.030
31 窗口D 售出火車票No.031
32 窗口D 售出火車票No.032
33 窗口D 售出火車票No.033
34 窗口D 售出火車票No.034
35 窗口C 售出火車票No.035
36 窗口C 售出火車票No.036
37 窗口C 售出火車票No.037
38 窗口C 售出火車票No.038
39 窗口C 售出火車票No.039
40 窗口C 售出火車票No.040
41 窗口A 售出火車票No.041
42 窗口A 售出火車票No.042
43 窗口A 售出火車票No.043
44 窗口A 售出火車票No.044
45 窗口A 售出火車票No.045
46 窗口A 售出火車票No.046
47 窗口A 售出火車票No.047
48 窗口B 售出火車票No.048
49 窗口B 售出火車票No.049
50 窗口B 售出火車票No.050
51 窗口B 售出火車票No.051
52 窗口B 售出火車票No.052
53 窗口B 售出火車票No.053
54 ...     ...    ....
55 窗口D 售出火車票No.974
56 窗口D 售出火車票No.975
57 窗口D 售出火車票No.976
58 窗口C 售出火車票No.977
59 窗口C 售出火車票No.978
60 窗口C 售出火車票No.979
61 窗口C 售出火車票No.980
62 窗口C 售出火車票No.981
63 窗口C 售出火車票No.982
64 窗口C 售出火車票No.983
65 窗口C 售出火車票No.984
66 窗口C 售出火車票No.985
67 窗口A 售出火車票No.986
68 窗口A 售出火車票No.987
69 窗口A 售出火車票No.988
70 窗口A 售出火車票No.989
71 窗口A 售出火車票No.990
72 窗口A 售出火車票No.991
73 窗口B 售出火車票No.992
74 窗口B 售出火車票No.993
75 窗口B 售出火車票No.994
76 窗口B 售出火車票No.995
77 窗口B 售出火車票No.996
78 窗口B 售出火車票No.997
79 窗口B 售出火車票No.998
80 窗口A 售出火車票No.999
81 窗口C 售出火車票No.1,000
82 車票已售罄!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM