国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

Java實(shí)戰之多線(xiàn)程模擬站點(diǎn)售票

發(fā)布時(shí)間:2021-07-05 18:40 來(lái)源:腳本之家 閱讀:0 作者:wayne_lee_lwc 欄目: 開(kāi)發(fā)技術(shù)

目錄

一、實(shí)驗題目

二、分析

哦吼,這次的實(shí)驗題目是一道非常經(jīng)典的多線(xiàn)程買(mǎi)票問(wèn)題。題目要求我們創(chuàng )建5個(gè)線(xiàn)程來(lái)模擬賣(mài)票,當然這其中就包含多線(xiàn)程存在也就是我們要解決的問(wèn)題,重復賣(mài)票和超額賣(mài)票。即多個(gè)窗口賣(mài)出同一張票以及窗口賣(mài)出非正數編號的票。

不過(guò)這個(gè)問(wèn)題可以先放一下,我們先來(lái)創(chuàng )建基礎的線(xiàn)程模型,并在主方法中創(chuàng )建五個(gè)線(xiàn)程讓他們跑起來(lái);

話(huà)不多說(shuō),上代碼。

public class Ticket {

	public static void main(String[] args) {
		
		for(int i = 1;i <= 5;i++) {
			//創(chuàng  )建5個(gè)線(xiàn)程并啟動(dòng)他們
			//注意一定要使用Thread類(lèi)創(chuàng  )建線(xiàn)程并使用start方法啟動(dòng)
			//而不是直接創(chuàng  )建TicketSeller對象調用run方法!!!!!!
			new Thread(new TicketSeller(i)).start();
		}
	}
}

//售票類(lèi),實(shí)現Runnable接口,可以作為線(xiàn)程執行對象
class TicketSeller implements Runnable{

	//該售票窗口編號
	private int code;
	
	public TicketSeller(int code) {
		this.code = code;
	}
	
	@Override
	public void run() {
		for(int i = 0;i < 5;i++) {
			System.out.println(code + "號窗口");
			
			//為了使線(xiàn)程能夠交替執行,打印完成語(yǔ)句讓線(xiàn)程休眠一小會(huì )
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

代碼的含義和需要注意的點(diǎn)都在注釋里面了,一定要看注釋?zhuān)。。?/strong>

運行結果就是:

后面太長(cháng)了就不放了。。。。

完成了基礎的多線(xiàn)程框架搭建后,我們來(lái)為每個(gè)線(xiàn)程執行過(guò)程中加入賣(mài)票的程序

首先要解決的一個(gè)問(wèn)題是:票存在哪里?。毋庸置疑的是由于是多線(xiàn)程并發(fā)的售票,因此票這個(gè)變量一定是被多個(gè)線(xiàn)程所共享的,而不能是每個(gè)線(xiàn)程對象自己的屬性。

一個(gè)可行的方案是在TicketSellet類(lèi)中定義靜態(tài)的票計數,這樣所有的線(xiàn)程訪(fǎng)問(wèn)票的時(shí)候訪(fǎng)問(wèn)的都是同一個(gè)票計數變量。

另一個(gè)可行方案是使用一個(gè)對象管理票,票計數是這個(gè)對象的成員,并且讓每個(gè)TicketSeller持有相同的對象。那么多個(gè)線(xiàn)程也同樣共享票計數。

當然,可行的方案還有很多,現在我們先來(lái)實(shí)現第一種,在之后的改進(jìn)中,我們還會(huì )用到第二種。

先來(lái)一個(gè)沒(méi)有加鎖的寫(xiě)法,看看他的問(wèn)題

//售票類(lèi),實(shí)現Runnable接口,可以作為線(xiàn)程執行對象
class TicketSeller implements Runnable{

	//票數
	private static int tickets = 100;
	
	//該售票窗口編號
	private int code;
	
	public TicketSeller(int code) {
		this.code = code;
	}
	
	@Override
	public void run() {
			
		//如果有票就一直賣(mài)
		while(tickets > 0) {
			System.out.println(code + "_____" + tickets--);
			
			//賣(mài)過(guò)票之后休眠一小會(huì )等待其他線(xiàn)程操作
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
			
	}
	
}

這段不加鎖的代碼會(huì )遇到許多很尷尬的問(wèn)題,首先一個(gè),多線(xiàn)程之間的重復賣(mài)票:

除了重復賣(mài)票,還有超額賣(mài)票的行為:

這當然是不能容忍的,解決辦法是在賣(mài)票過(guò)程對tickets變量加鎖,使得每次只能有一個(gè)線(xiàn)程進(jìn)入賣(mài)票的環(huán)節而其他線(xiàn)程只能循環(huán)等待:

但是這樣處理并不能完全結局上面的問(wèn)題,盡管每次只能一個(gè)線(xiàn)程進(jìn)入賣(mài)票階段阻止了重復賣(mài)票。但是超額賣(mài)票的行為依舊會(huì )發(fā)生:


好嘛,這次非常嚴重

原因嗎其實(shí)并不復雜,我們加鎖只是能阻止多個(gè)進(jìn)程進(jìn)入賣(mài)票程序,但是會(huì )有其他程序達成判斷條件,執行到賣(mài)票程序之前等待進(jìn)入,如果一個(gè)線(xiàn)程將票賣(mài)完而此時(shí)有其他程序剛好等待進(jìn)入,那么就會(huì )出現上面的情況。

所以我們還需要加上一道保險:

經(jīng)過(guò)這樣的處理,票子就可以放心的賣(mài)出而不用擔心重或者賣(mài)超了

三、完整代碼:

public class Ticket {

	public static void main(String[] args) {
		
		for(int i = 1;i <= 5;i++) {
			//創(chuàng  )建5個(gè)線(xiàn)程并啟動(dòng)他們
			//注意一定要使用Thread類(lèi)創(chuàng  )建線(xiàn)程并使用start方法啟動(dòng)
			//而不是直接創(chuàng  )建TicketSeller對象調用run方法!!!!!!
			new Thread(new TicketSeller(i)).start();
		}
	}
}

//售票類(lèi),實(shí)現Runnable接口,可以作為線(xiàn)程執行對象
class TicketSeller implements Runnable{

	//票數
	private static int tickets = 100;

	//同步鎖
	private static Object lock = new Object();
	
	//該售票窗口編號
	private int code;
	
	public TicketSeller(int code) {
		this.code = code;
	}
	
	@Override
	public void run() {
			
		//如果有票就一直賣(mài)
		while(tickets > 0) {
			synchronized (lock) {
				
				//如果票賣(mài)完了則跳出
				if(tickets <= 0) {
					break;
				}
				
				System.out.println(code + "_____" + tickets--);
				
				//賣(mài)過(guò)票之后休眠一小會(huì )等待其他線(xiàn)程操作
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
			
	}
	
}

在前面我們還提出了另一種方案,就是使用一個(gè)對象管理票的售賣(mài)。這種方案就不展開(kāi)啰嗦了,直接上代碼:

public class Ticket {

	public static void main(String[] args) {
		//創(chuàng  )建一個(gè)票管理對象,票數為100
		TicketSet ts = new TicketSet(100);
	
		//創(chuàng  )建5個(gè)線(xiàn)程,使用同一個(gè)票管理對象
		for(int i = 1;i <= 5;i++) {
			new Thread(new TicketSeller(ts, i)).start();
		}
	}
}

//票管理類(lèi)
class TicketSet{
	
	//票數
	private int tickets;
	
	public TicketSet(int tickets) {
		this.tickets = tickets;
	}
	
	
	private boolean hasTicket() {
		return tickets > 0;
	}
	
	//售票方法,使用同步鎖,每次只能有一個(gè)線(xiàn)程訪(fǎng)問(wèn)該方法
	//返回結果為是否賣(mài)出去票
	synchronized public boolean sellTicket(int code) {
		if(hasTicket()) {
			System.out.println(code + "_____" + tickets--);
			return true;
		}else {
			return false;
		}
	}
}

//售票類(lèi)
class TicketSeller implements Runnable{
	//票管理對象
	private TicketSet ts;

	private int code;
	
	public TicketSeller(TicketSet ts,int code) {
		this.ts = ts;
		this.code = code;
	}

	@Override
	public void run() {
		//嘗試調用票管理的售票方法,售票成功后休眠一小會(huì )
		while(ts.sellTicket(code)){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

到此這篇關(guān)于Java實(shí)戰之多線(xiàn)程模擬站點(diǎn)售票的文章就介紹到這了,更多相關(guān)多線(xiàn)程模擬站點(diǎn)售票內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。

人人色在线视频播放| 一本大道久久东京热无码AV| 亚洲国产成人精品女人久久久| 日韩精品专区AV无码| 越南女子杂交内射BBWXZ| 无码成人AV在线一区二区|