您好,登錄后才能下訂單哦!
1.前言
為了學習多線程共享與通信,我們模擬一個火車售票系統,假設有10張火車票,三個窗口(也就是三個線程)同時進行售票。
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, "一號窗口"); Thread t2 = new Thread(tw, "二號窗口"); Thread t3 = new Thread(tw, "三號窗口"); 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(); } } } } }
打印結果:
還剩余票:10張 還剩余票:10張 還剩余票:10張 二號窗口賣出一張火車票,還剩7張 還剩余票:7張 三號窗口賣出一張火車票,還剩8張 一號窗口賣出一張火車票,還剩9張 還剩余票:6張 還剩余票:6張 二號窗口賣出一張火車票,還剩6張 還剩余票:4張 三號窗口賣出一張火車票,還剩4張 還剩余票:3張 一號窗口賣出一張火車票,還剩5張 三號窗口賣出一張火車票,還剩2張 還剩余票:2張 三號窗口賣出一張火車票,還剩1張 還剩余票:1張 三號窗口賣出一張火車票,還剩0張 余票不足,暫停出售! 二號窗口賣出一張火車票,還剩3張 余票不足,暫停出售! 還剩余票:2張 一號窗口賣出一張火車票,還剩-1張 余票不足,暫停出售!
上面結果,可以清楚地看到,由于三個線程可以同時訪問一個任務,也就是售票任務,會出現火車票還剩-1張這種不合實際的問題,之所以出現是因為假設在某一瞬間,tickets為1時,tickets > 0為true,A線程運行到tickets--這一行代碼,此時還沒有減去1,同時另外一個線程B剛好運行到tickets > 0這一行代碼,判斷成功,開始執行賣票,此時A線程減去一張票,tickets=0,然后B線程又減去一張,則剩-1張。所以此時需要用到同步鎖synchronized。保證某一時刻只能有一個線程執行售票功能。
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, "一號窗口"); Thread t2 = new Thread(tw, "二號窗口"); Thread t3 = new Thread(tw, "三號窗口"); 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() + "準備出票,還剩余票:" + 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() + "準備出票,還剩余票:" + 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(); } } } } } }
結果:
一號窗口準備出票,還剩余票:10張 一號窗口賣出一張火車票,還剩9張 一號窗口準備出票,還剩余票:9張 一號窗口賣出一張火車票,還剩8張 一號窗口準備出票,還剩余票:8張 一號窗口賣出一張火車票,還剩7張 一號窗口準備出票,還剩余票:7張 一號窗口賣出一張火車票,還剩6張 一號窗口準備出票,還剩余票:6張 一號窗口賣出一張火車票,還剩5張 一號窗口準備出票,還剩余票:5張 一號窗口賣出一張火車票,還剩4張 一號窗口準備出票,還剩余票:4張 一號窗口賣出一張火車票,還剩3張 一號窗口準備出票,還剩余票:3張 一號窗口賣出一張火車票,還剩2張 一號窗口準備出票,還剩余票:2張 一號窗口賣出一張火車票,還剩1張 一號窗口準備出票,還剩余票:1張 一號窗口賣出一張火車票,還剩0張 余票不足,暫停出售!
synchronized:
synchronized是Java中的關鍵字,是一種同步鎖。它修飾的對象有以下幾種:
1. 修飾一個代碼塊,被修飾的代碼塊稱為同步語句塊,其作用的范圍是大括號{}括起來的代碼,作用的對象是調用這個代碼塊的對象;
2. 修飾一個方法,被修飾的方法稱為同步方法,其作用的范圍是整個方法,作用的對象是調用這個方法的對象;
3. 修改一個靜態的方法,其作用的范圍是整個靜態方法,作用的對象是這個類的所有對象;
4. 修改一個類,其作用的范圍是synchronized后面括號括起來的部分,作用主的對象是這個類的所有對象。
以上這篇java多線程之火車售票系統模擬實例就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。