欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2021年05月24日 11:50:19   作者:wayne_lee_lwc  
今天帶大家來(lái)練習(xí)Java實(shí)戰(zhàn),文中多線程模擬站點(diǎn)售票這個(gè)問題作了詳細(xì)的介紹,對(duì)正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下

一、實(shí)驗(yàn)題目

在這里插入圖片描述

二、分析

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

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

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

public class Ticket {

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

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

	//該售票窗口編號(hào)
	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 + "號(hào)窗口");
			
			//為了使線程能夠交替執(zhí)行,打印完成語(yǔ)句讓線程休眠一小會(huì)
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

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

運(yùn)行結(jié)果就是:

在這里插入圖片描述

后面太長(zhǎng)了就不放了。。。。

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

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

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

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

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

先來(lái)一個(gè)沒有加鎖的寫法,看看他的問題

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

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

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

在這里插入圖片描述

除了重復(fù)賣票,還有超額賣票的行為:

在這里插入圖片描述

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

在這里插入圖片描述

在這里插入圖片描述

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

在這里插入圖片描述

好嘛,這次非常嚴(yán)重

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

所以我們還需要加上一道保險(xiǎn):

在這里插入圖片描述

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

三、完整代碼:

public class Ticket {

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

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

	//票數(shù)
	private static int tickets = 100;

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

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

public class Ticket {

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

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

//售票類
class TicketSeller implements Runnable{
	//票管理對(duì)象
	private TicketSet ts;

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

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

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

相關(guān)文章

  • springmvc中下載中文文件名稱為下劃線的解決方案

    springmvc中下載中文文件名稱為下劃線的解決方案

    這篇文章主要介紹了springmvc中下載中文文件名稱為下劃線的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • idea為java程序添加啟動(dòng)參數(shù)的問題解析(program?arguments,vm?arguments,Environment?variable)并在程序中獲取使用

    idea為java程序添加啟動(dòng)參數(shù)的問題解析(program?arguments,vm?arguments,Envi

    這篇文章主要介紹了idea為java程序添加啟動(dòng)參數(shù)的問題解析(program?arguments,vm?arguments,Environment?variable)并在程序中獲取使用,本文給大家分享問題描述及解決方法,需要的朋友可以參考下
    2023-09-09
  • Java可重入鎖ReentrantLock詳解

    Java可重入鎖ReentrantLock詳解

    這篇文章主要介紹了Java可重入鎖ReentrantLock詳解,ReentrantLock是一個(gè)可重入且獨(dú)占式的鎖,是一種遞歸無(wú)阻塞的同步機(jī)制,它支持重復(fù)進(jìn)入鎖,即該鎖能夠支持一個(gè)線程對(duì)資源的重復(fù)加鎖,除此之外,該鎖的還支持獲取鎖時(shí)的公平和非公平性選擇,需要的朋友可以參考下
    2023-09-09
  • Mybatis自定義TypeHandler解決特殊類型轉(zhuǎn)換問題詳解

    Mybatis自定義TypeHandler解決特殊類型轉(zhuǎn)換問題詳解

    這篇文章主要介紹了Mybatis自定義TypeHandler解決特殊類型轉(zhuǎn)換問題詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • Java中jar包運(yùn)行后顯示:沒有主清單屬性的解決方案

    Java中jar包運(yùn)行后顯示:沒有主清單屬性的解決方案

    這篇文章主要介紹了Java中jar包運(yùn)行后顯示:沒有主清單屬性的解決方案,文中給大家分析了三個(gè)主要原因,并通過(guò)代碼示例和圖文講解的非常詳細(xì),需要的朋友可以參考下
    2024-04-04
  • Mybatis配置之<typeAliases>別名配置元素解析

    Mybatis配置之<typeAliases>別名配置元素解析

    這篇文章主要介紹了Mybatis配置之<typeAliases>別名配置元素解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • MyBatis攔截器:給參數(shù)對(duì)象屬性賦值的實(shí)例

    MyBatis攔截器:給參數(shù)對(duì)象屬性賦值的實(shí)例

    下面小編就為大家?guī)?lái)一篇MyBatis攔截器:給參數(shù)對(duì)象屬性賦值的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-04-04
  • Java中BigDecimal與0比較的一個(gè)坑實(shí)戰(zhàn)記錄

    Java中BigDecimal與0比較的一個(gè)坑實(shí)戰(zhàn)記錄

    BigDecimal屬于大數(shù)據(jù),精度極高,不屬于基本數(shù)據(jù)類型,屬于java對(duì)象,下面這篇文章主要給大家介紹了關(guān)于Java中BigDecimal與0比較的一個(gè)坑的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • 一文教你如何使用AES對(duì)接口參數(shù)進(jìn)行加密

    一文教你如何使用AES對(duì)接口參數(shù)進(jìn)行加密

    這篇文章主要是想為大家介紹一下如何使用AES實(shí)現(xiàn)對(duì)接口參數(shù)進(jìn)行加密,文中的示例代碼簡(jiǎn)潔易懂,具有一定的借鑒價(jià)值,需要的小伙伴可以了解一下
    2023-08-08
  • PowerDesigner連接數(shù)據(jù)庫(kù)的實(shí)例詳解

    PowerDesigner連接數(shù)據(jù)庫(kù)的實(shí)例詳解

    這篇文章主要介紹了PowerDesigner連接數(shù)據(jù)庫(kù)的實(shí)例詳解的相關(guān)資料,如有疑問請(qǐng)留言或者到本站社區(qū)交流討論,需要的朋友可以參考下
    2017-10-10

最新評(píng)論