天天看點

多線程實作賣票的例子

以賣票的例子來介紹多線程和資源共享。

  賣票是包含一系列動作的過程,有各種操作,例如查詢票、收錢、數錢、出票等,其中有一個操作是每次賣掉一張,就将總的票數減去1。有10張票,如果一個人賣票,先做查票、收錢、數錢等各種操作,再将總的票數減去1,效率很低。如果多個人賣票,每個人都是做同樣的操作,數錢、檢查錢,最後将總的票數減1,這樣效率高。但是有一個問題,如果出現兩個人同時将總的票數減掉了1,例如,A、B兩個人同時讀取到票的總數是10,A從中減去1,同時B也從中減去1,總數顯示是9,其實票隻有8張。導緻資料錯誤。

  按照正常邏輯,同一時刻隻允許一個人來從總票數中減去1,A讀取總票數,再減去1的過程中,B必須等待,等A操作完了,B才能進行。其實票就是共享資源,一次隻能由一個人通路。這裡就要用到同步機制,即鎖機制,使用關鍵詞synchronized将讀取總的票數,并減去1的操作鎖定,使得一次隻能由一個人通路。每個售票員就是一個線程,多個售票員進行同一項賣票任務。

  synchronized原理是,執行synchronized部分代碼的時候必須需要對象鎖,而一個對象隻有一個鎖,隻有執行完synchronized裡面的代碼後釋放鎖,其他線程才可以獲得鎖,那麼就保證了同一時刻隻有一個線程通路synchronized裡面的代碼。使得資源共享的關鍵是,隻有一個執行個體,synchronized使用的是同一把鎖,用執行個體的鎖或者定義一個執行個體。這就需要使用實作Runnable接口的方式,實作多線程,這樣傳入的是一個執行個體。繼承Thread的方式,傳入的是多個執行個體,每個執行個體都有一個鎖,那就無法實作控制。代碼如下:

public class SellTicketsThread implements Runnable{
	
	private int ticketCount = 50;
	Object lockObject = new Object();

	public SellTicketsThread() {
	}

	@Override
	public void run() {
		while(ticketCount > 0){
			sellTicket();
			/**
			 目前線程休眠,好讓其他線程繼續執行
			*/
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void sellTicket(){
		synchronized(lockObject){
			if(ticketCount > 0){
				System.out.println(Thread.currentThread().getName()+"正在賣第:"+ticketCount+"張票"+
									",還剩"+(ticketCount-1)+"張票");
				ticketCount--;
			} else{
				System.out.println("票已賣完");
				return;
			}
		}
	}
	
	

}
           

主函數調用:

public class SellTicketsMain {

	public SellTicketsMain() {
	}
	
	public static void main(String[] args) {
		SellTicketsThread sellTicketsThread = new SellTicketsThread();
		Thread firstThread = new Thread(sellTicketsThread, "線程1");
		Thread secondThread = new Thread(sellTicketsThread, "線程2");
		Thread thirdThread = new Thread(sellTicketsThread, "線程3");
		Thread fourthThread = new Thread(sellTicketsThread, "線程4");
		Thread fifthThread = new Thread(sellTicketsThread, "線程5");
		firstThread.start();
		secondThread.start();
		thirdThread.start();
		fourthThread.start();
		fifthThread.start();
	}

}
           

執行結果:

線程1正在賣第:50張票,還剩49張票

線程2正在賣第:49張票,還剩48張票

線程3正在賣第:48張票,還剩47張票

線程4正在賣第:47張票,還剩46張票

線程5正在賣第:46張票,還剩45張票

線程4正在賣第:45張票,還剩44張票

線程2正在賣第:44張票,還剩43張票

線程1正在賣第:43張票,還剩42張票

線程3正在賣第:42張票,還剩41張票

線程5正在賣第:41張票,還剩40張票

線程5正在賣第:40張票,還剩39張票

線程4正在賣第:39張票,還剩38張票

線程2正在賣第:38張票,還剩37張票

線程1正在賣第:37張票,還剩36張票

線程3正在賣第:36張票,還剩35張票

線程5正在賣第:35張票,還剩34張票

線程3正在賣第:34張票,還剩33張票

線程1正在賣第:33張票,還剩32張票

線程2正在賣第:32張票,還剩31張票

線程4正在賣第:31張票,還剩30張票

線程5正在賣第:30張票,還剩29張票

線程3正在賣第:29張票,還剩28張票

線程1正在賣第:28張票,還剩27張票

線程2正在賣第:27張票,還剩26張票

線程4正在賣第:26張票,還剩25張票

線程2正在賣第:25張票,還剩24張票

線程5正在賣第:24張票,還剩23張票

線程3正在賣第:23張票,還剩22張票

線程1正在賣第:22張票,還剩21張票

線程4正在賣第:21張票,還剩20張票

線程4正在賣第:20張票,還剩19張票

線程2正在賣第:19張票,還剩18張票

線程5正在賣第:18張票,還剩17張票

線程3正在賣第:17張票,還剩16張票

線程1正在賣第:16張票,還剩15張票

線程1正在賣第:15張票,還剩14張票

線程4正在賣第:14張票,還剩13張票

線程2正在賣第:13張票,還剩12張票

線程5正在賣第:12張票,還剩11張票

線程3正在賣第:11張票,還剩10張票

線程2正在賣第:10張票,還剩9張票

線程3正在賣第:9張票,還剩8張票

線程5正在賣第:8張票,還剩7張票

線程1正在賣第:7張票,還剩6張票

線程4正在賣第:6張票,還剩5張票

線程3正在賣第:5張票,還剩4張票

線程5正在賣第:4張票,還剩3張票

線程1正在賣第:3張票,還剩2張票

線程4正在賣第:2張票,還剩1張票

線程2正在賣第:1張票,還剩0張票

繼續閱讀