java多線程之火車售票系統(tǒng)模擬實(shí)例
1.前言
為了學(xué)習(xí)多線程共享與通信,我們模擬一個(gè)火車售票系統(tǒng),假設(shè)有10張火車票,三個(gè)窗口(也就是三個(gè)線程)同時(shí)進(jìn)行售票。
2.非同步代碼
package com.tl.skyLine.thread;
/**
* Created by tl on 17/3/6.
*/
public class SellTicket {
public static void main(String[] args) {
TicketWindow tw = new TicketWindow();
Thread t1 = new Thread(tw, "一號(hào)窗口");
Thread t2 = new Thread(tw, "二號(hào)窗口");
Thread t3 = new Thread(tw, "三號(hào)窗口");
t1.start();
t2.start();
t3.start();
}
}
class TicketWindow implements Runnable {
private int tickets = 10;
@Override
public void run() {
while (true) {
if (tickets > 0) {
System.out.println("還剩余票:" + tickets + "張");
tickets--;
System.out.println(Thread.currentThread().getName() + "賣出一張火車票,還剩" + tickets + "張");
} else {
System.out.println("余票不足,暫停出售!");
// wait,notify和notifyAll只能在同步控制方法或者同步控制塊里面使用,而sleep可以在任何地方使用
try {
Thread.sleep(1000 * 60 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
打印結(jié)果:
還剩余票:10張 還剩余票:10張 還剩余票:10張 二號(hào)窗口賣出一張火車票,還剩7張 還剩余票:7張 三號(hào)窗口賣出一張火車票,還剩8張 一號(hào)窗口賣出一張火車票,還剩9張 還剩余票:6張 還剩余票:6張 二號(hào)窗口賣出一張火車票,還剩6張 還剩余票:4張 三號(hào)窗口賣出一張火車票,還剩4張 還剩余票:3張 一號(hào)窗口賣出一張火車票,還剩5張 三號(hào)窗口賣出一張火車票,還剩2張 還剩余票:2張 三號(hào)窗口賣出一張火車票,還剩1張 還剩余票:1張 三號(hào)窗口賣出一張火車票,還剩0張 余票不足,暫停出售! 二號(hào)窗口賣出一張火車票,還剩3張 余票不足,暫停出售! 還剩余票:2張 一號(hào)窗口賣出一張火車票,還剩-1張 余票不足,暫停出售!
上面結(jié)果,可以清楚地看到,由于三個(gè)線程可以同時(shí)訪問一個(gè)任務(wù),也就是售票任務(wù),會(huì)出現(xiàn)火車票還剩-1張這種不合實(shí)際的問題,之所以出現(xiàn)是因?yàn)榧僭O(shè)在某一瞬間,tickets為1時(shí),tickets > 0為true,A線程運(yùn)行到tickets--這一行代碼,此時(shí)還沒有減去1,同時(shí)另外一個(gè)線程B剛好運(yùn)行到tickets > 0這一行代碼,判斷成功,開始執(zhí)行賣票,此時(shí)A線程減去一張票,tickets=0,然后B線程又減去一張,則剩-1張。所以此時(shí)需要用到同步鎖synchronized。保證某一時(shí)刻只能有一個(gè)線程執(zhí)行售票功能。
3.同步代碼
package com.tl.skyLine.thread;
/**
* Created by tl on 17/3/6.
*/
public class SellTicket {
public static void main(String[] args) {
TicketWindow tw = new TicketWindow();
Thread t1 = new Thread(tw, "一號(hào)窗口");
Thread t2 = new Thread(tw, "二號(hào)窗口");
Thread t3 = new Thread(tw, "三號(hào)窗口");
t1.start();
t2.start();
t3.start();
}
}
class TicketWindow implements Runnable {
private int tickets = 10;
@Override
public synchronized void run() {
while (true) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "準(zhǔn)備出票,還剩余票:" + tickets + "張");
tickets--;
System.out.println(Thread.currentThread().getName() + "賣出一張火車票,還剩" + tickets + "張");
} else {
System.out.println("余票不足,暫停出售!");
// wait,notify和notifyAll只能在同步控制方法或者同步控制塊里面使用,而sleep可以在任何地方使用
try {
Thread.sleep(1000 * 60 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
等同于:
class TicketWindow implements Runnable {
private int tickets = 10;
@Override
public void run() {
while (true) {
synchronized (this) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "準(zhǔn)備出票,還剩余票:" + tickets + "張");
tickets--;
System.out.println(Thread.currentThread().getName() + "賣出一張火車票,還剩" + tickets + "張");
} else {
System.out.println("余票不足,暫停出售!");
// wait,notify和notifyAll只能在同步控制方法或者同步控制塊里面使用,而sleep可以在任何地方使用
try {
Thread.sleep(1000 * 60 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
結(jié)果:
一號(hào)窗口準(zhǔn)備出票,還剩余票:10張 一號(hào)窗口賣出一張火車票,還剩9張 一號(hào)窗口準(zhǔn)備出票,還剩余票:9張 一號(hào)窗口賣出一張火車票,還剩8張 一號(hào)窗口準(zhǔn)備出票,還剩余票:8張 一號(hào)窗口賣出一張火車票,還剩7張 一號(hào)窗口準(zhǔn)備出票,還剩余票:7張 一號(hào)窗口賣出一張火車票,還剩6張 一號(hào)窗口準(zhǔn)備出票,還剩余票:6張 一號(hào)窗口賣出一張火車票,還剩5張 一號(hào)窗口準(zhǔn)備出票,還剩余票:5張 一號(hào)窗口賣出一張火車票,還剩4張 一號(hào)窗口準(zhǔn)備出票,還剩余票:4張 一號(hào)窗口賣出一張火車票,還剩3張 一號(hào)窗口準(zhǔn)備出票,還剩余票:3張 一號(hào)窗口賣出一張火車票,還剩2張 一號(hào)窗口準(zhǔn)備出票,還剩余票:2張 一號(hào)窗口賣出一張火車票,還剩1張 一號(hào)窗口準(zhǔn)備出票,還剩余票:1張 一號(hào)窗口賣出一張火車票,還剩0張 余票不足,暫停出售!
synchronized:
synchronized是Java中的關(guān)鍵字,是一種同步鎖。它修飾的對(duì)象有以下幾種:
1. 修飾一個(gè)代碼塊,被修飾的代碼塊稱為同步語句塊,其作用的范圍是大括號(hào){}括起來的代碼,作用的對(duì)象是調(diào)用這個(gè)代碼塊的對(duì)象;
2. 修飾一個(gè)方法,被修飾的方法稱為同步方法,其作用的范圍是整個(gè)方法,作用的對(duì)象是調(diào)用這個(gè)方法的對(duì)象;
3. 修改一個(gè)靜態(tài)的方法,其作用的范圍是整個(gè)靜態(tài)方法,作用的對(duì)象是這個(gè)類的所有對(duì)象;
4. 修改一個(gè)類,其作用的范圍是synchronized后面括號(hào)括起來的部分,作用主的對(duì)象是這個(gè)類的所有對(duì)象。
以上這篇java多線程之火車售票系統(tǒng)模擬實(shí)例就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java數(shù)據(jù)結(jié)構(gòu)之HashMap和HashSet
這篇文章主要介紹了HashMap和HashSet,什么是哈希表以及HashMap的部分源碼解讀,想了解更多的小伙伴,可以參考閱讀本文2023-03-03
Java String字符串內(nèi)容實(shí)現(xiàn)添加雙引號(hào)
這篇文章主要介紹了Java String字符串內(nèi)容實(shí)現(xiàn)添加雙引號(hào),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09
@CacheEvict + redis實(shí)現(xiàn)批量刪除緩存
這篇文章主要介紹了@CacheEvict + redis實(shí)現(xiàn)批量刪除緩存方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
JAVA中出現(xiàn)異常、拋出異常后續(xù)代碼是否執(zhí)行情況詳析
當(dāng)產(chǎn)生異常后,并在異常處理器中進(jìn)行執(zhí)行之后,程序會(huì)是如何的一種狀態(tài),是終止還是繼續(xù)執(zhí)行處理之后的代碼呢,下面這篇文章主要給大家介紹了關(guān)于JAVA中出現(xiàn)異常、拋出異常后續(xù)代碼是否執(zhí)行情況的相關(guān)資料,需要的朋友可以參考下2024-05-05
Java中關(guān)于char類型變量能夠輸出中文的問題
這篇文章主要介紹了Java中關(guān)于char類型變量能夠輸出中文的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12

