首先看題目描述:
假設有火車票100張,創建4個線程模擬4個售票點,每100ms售出一張,打印出售票過程,格式如下:
窗口3:賣出第100張票
窗口4:賣出第99張票
............
............
簡單的思路就是創建一個類,首先肯定要去繼承Thread。開啟線程,由於是4個窗口,肯定要開啟4個線程。然后讓每個線程去輸出結果,也就是賣出去的票。這里很多人想不到如何讓4個線程不打印重復的票。(比如4個線程都賣出去了第100張票,這顯然是不合理的)。
看代碼:
1 package com.lesson.thread; 2 3 public class MyThread { 4 5 public static void main(String[] args) { 6 Ticket sell1 = new Ticket(); 7 Ticket sell2 = new Ticket(); 8 Ticket sell3 = new Ticket(); 9 Ticket sell4 = new Ticket(); 10 sell1.setName("窗口1"); 11 sell2.setName("窗口2"); 12 sell3.setName("窗口3"); 13 sell4.setName("窗口4"); 14 sell1.start(); 15 sell2.start(); 16 sell3.start(); 17 sell4.start(); 18 } 19 } 20 class Ticket extends Thread { 21 private static int tickets = 100;//這里設置成static,目的是讓每個線程共享這個變量。以免出現重復打印的現象。 22 @Override 23 public void run() { 24 while(true) { 25 if(tickets <= 0) { 26 break; 27 } 2829 System.out.println(getName()+":買出第"+tickets--+"張票。");//賣出一張減一張票 30 31 } 32 } 33 34 }
可能你已經看到了你想要的結果了。但是,還沒完。目前代碼寫到這里是有問題的!!!
為什么?
看下面的代碼:
package thread; public class Mythread { public static void main(String[] args) { Ticket sell1 = new Ticket(); Ticket sell2 = new Ticket(); Ticket sell3 = new Ticket(); Ticket sell4 = new Ticket(); sell1.setName("窗口1"); sell2.setName("窗口2"); sell3.setName("窗口3"); sell4.setName("窗口4"); sell1.start(); sell2.start(); sell3.start(); sell4.start(); } } class Ticket extends Thread { private static int tickets = 100; @Override public void run() { while(true) { if(tickets <= 0) { break; } try { Thread.sleep(10); //讓進來的線程睡10ms;線程1,2,3,4都睡在這 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName()+":買出了第"+tickets--+"張票。"); } } }
與開始的代碼不同在於讓進來的線程睡一會。可以看到如下運行結果:
窗口2:買出了第0張票。
窗口3:買出了第-1張票。
窗口1:買出了第-2張票。
這里編者調出來了出問題的地方。可以看到怎么會第0,-1,-2張票???
做出解釋:
其實在這里讓線程睡一會就是為了演示這里有很多行代碼要執行。假設票已經賣到第1張了,也就是tickets=1,然后第一條線程進來判斷 tickets <= 0 ?不成立,然后線程1要睡 10ms,緊接着,線程2進來,這時 tickets 還是為1,因為線程1在睡,tickets 沒有減 。然后線程2判斷 tickets <= 0 ? 還是不成立,線程2又開始睡。同樣,線程3,線程4都睡了。 這時的tickets 還是等於1的。然后線程1先醒過來,開始輸出結果,tickets 減了1。可是這是其他的線程還是經過while里面的判斷語句進來了的,只是睡了。所以當其他線程醒過來的時候,還是會打印出結果的。也就出現了上面的問題。
解決方法:
多線程並發改變同一變量,為了解決,采用同步代碼塊synchronized。里面加任意的對象,但是不能加this,因為這里創建了四個線程,每一個線程都有自己的對象,所以是四個不同的對象,沒有用。所以這里不能用this,必須鎖在同一個對象里才行。而Thickets.class這是唯一的。
package thread; public class Mythread { public static void main(String[] args) { Ticket sell1 = new Ticket(); Ticket sell2 = new Ticket(); Ticket sell3 = new Ticket(); Ticket sell4 = new Ticket(); sell1.setName("窗口1"); sell2.setName("窗口2"); sell3.setName("窗口3"); sell4.setName("窗口4"); sell1.start(); sell2.start(); sell3.start(); sell4.start(); } } class Ticket extends Thread { private static int tickets = 100; @Override public void run() { while(true) { synchronized (Ticket.class) {//同步代碼塊 if(tickets <= 0) { break; } try { Thread.sleep(100); //每100ms賣出一張 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName()+":買出了第"+tickets--+"張票。"); } } } }
