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

Java通過(guò)賣(mài)票理解多線程

 更新時(shí)間:2017年09月12日 09:11:10   作者:瘦魚(yú)  
本文主要介紹了一個(gè)多線程賣(mài)票的例子,通過(guò)賣(mài)票這個(gè)實(shí)例來(lái)介紹多線程的方式,加深理解,需要的朋友可以參考下

        以賣(mài)票的例子來(lái)介紹多線程和資源共享,下面我們來(lái)看看為什么要用賣(mài)票作為例子。

  賣(mài)票是包含一系列動(dòng)作的過(guò)程,有各種操作,例如查詢(xún)票、收錢(qián)、數(shù)錢(qián)、出票等,其中有一個(gè)操作是每次賣(mài)掉一張,就將總的票數(shù)減去1。有10張票,如果一個(gè)人賣(mài)票,先做查票、收錢(qián)、數(shù)錢(qián)等各種操作,再將總的票數(shù)減去1,效率很低。如果多個(gè)人賣(mài)票,每個(gè)人都是做同樣的操作,數(shù)錢(qián)、檢查錢(qián),最后將總的票數(shù)減1,這樣效率高。但是有一個(gè)問(wèn)題,如果出現(xiàn)兩個(gè)人同時(shí)將總的票數(shù)減掉了1,例如,A、B兩個(gè)人同時(shí)讀取到票的總數(shù)是10,A從中減去1,同時(shí)B也從中減去1,總數(shù)顯示是9,其實(shí)票只有8張。導(dǎo)致數(shù)據(jù)錯(cuò)誤。

  按照正常邏輯,同一時(shí)刻只允許一個(gè)人來(lái)從總票數(shù)中減去1,A讀取總票數(shù),再減去1的過(guò)程中,B必須等待,等A操作完了,B才能進(jìn)行。其實(shí)票就是共享資源,一次只能由一個(gè)人訪問(wèn)。這里就要用到同步機(jī)制,即鎖機(jī)制,使用關(guān)鍵詞synchronized將讀取總的票數(shù),并減去1的操作鎖定,使得一次只能由一個(gè)人訪問(wèn)。每個(gè)售票員就是一個(gè)線程,多個(gè)售票員進(jìn)行同一項(xiàng)賣(mài)票任務(wù)。

  synchronized原理是,執(zhí)行synchronized部分代碼的時(shí)候必須需要對(duì)象鎖,而一個(gè)對(duì)象只有一個(gè)鎖,只有執(zhí)行完synchronized里面的代碼后釋放鎖,其他線程才可以獲得鎖,那么就保證了同一時(shí)刻只有一個(gè)線程訪問(wèn)synchronized里面的代碼。使得資源共享的關(guān)鍵是,只有一個(gè)實(shí)例,synchronized使用的是同一把鎖,用實(shí)例的鎖或者定義一個(gè)實(shí)例。這就需要使用實(shí)現(xiàn)Runnable接口的方式,實(shí)現(xiàn)多線程,這樣傳入的是一個(gè)實(shí)例。繼承Thread的方式,傳入的是多個(gè)實(shí)例,每個(gè)實(shí)例都有一個(gè)鎖,那就無(wú)法實(shí)現(xiàn)控制。

具體代碼如下:

package com.test;
public class SaleTickets implements Runnable
{
  private int ticketCount = 10;// 總的票數(shù),這個(gè)是共享資源,多個(gè)線程都會(huì)訪問(wèn)
  Object mutex = new Object();// 鎖,自己定義的,或者使用實(shí)例的鎖
  /**
   * 賣(mài)票
   */
  public void sellTicket()
  {
    synchronized (mutex)// 當(dāng)操作的是共享數(shù)據(jù)時(shí),
            // 用同步代碼塊進(jìn)行包圍起來(lái),執(zhí)行里面的代碼需要mutex的鎖,但是mutex只有一個(gè)鎖。這樣在執(zhí)行時(shí),只能有一個(gè)線程執(zhí)行同步代碼塊里面的內(nèi)容
    {
      if (ticketCount > 0)
      {
        ticketCount--;
        System.out.println(Thread.currentThread().getName()
            + "正在賣(mài)票,還剩" + ticketCount + "張票");
      }
      else
      {
        System.out.println("票已經(jīng)賣(mài)完!");
        return;
      }
    }
  }
  public void run()
  {
    while (ticketCount > 0)// 循環(huán)是指線程不停的去賣(mài)票
    {
      sellTicket();
      /**
       * 在同步代碼塊里面睡覺(jué),和不睡效果是一樣 的,作用只是自已不執(zhí)行,也不讓線程執(zhí)行。sleep不釋放鎖,抱著鎖睡覺(jué)。其他線程拿不到鎖,也不能執(zhí)行同步代碼。wait()可以釋放鎖
       * 所以把睡覺(jué)放到同步代碼塊的外面,這樣賣(mài)完一張票就睡一會(huì),讓其他線程再賣(mài),這樣所有的線程都可以賣(mài)票
       */
      try
      {
        Thread.sleep(100);
      }
      catch (InterruptedException e)
      {
        e.printStackTrace();
      }
    }
  }
}

下面是調(diào)用:

package com.test;
public class TicketMain
{
  public static void main(String[] args)
  {
    SaleTickets runTicekt = new SaleTickets();//只定義了一個(gè)實(shí)例,這就只有一個(gè)Object mutex = new Object();即一個(gè)鎖。
    Thread th1 = new Thread(runTicekt, "窗口1");//每個(gè)線程等其他線程釋放該鎖后,才能執(zhí)行
    Thread th2 = new Thread(runTicekt, "窗口2");
    Thread th3 = new Thread(runTicekt, "窗口3");
    Thread th4 = new Thread(runTicekt, "窗口4");
    th1.start();
    th2.start();
    th3.start();
    th4.start();
  }
}

輸出:

窗口1正在賣(mài)票,還剩9張票
窗口4正在賣(mài)票,還剩8張票
窗口3正在賣(mài)票,還剩7張票
窗口2正在賣(mài)票,還剩6張票
窗口3正在賣(mài)票,還剩5張票
窗口2正在賣(mài)票,還剩4張票
窗口1正在賣(mài)票,還剩3張票
窗口4正在賣(mài)票,還剩2張票
窗口3正在賣(mài)票,還剩1張票
窗口1正在賣(mài)票,還剩0張票
票已經(jīng)賣(mài)完!

  這是多個(gè)線程,完成同一個(gè)任務(wù)的情況,即多個(gè)線程調(diào)用同一個(gè)實(shí)例,通過(guò)實(shí)現(xiàn)Runable接口實(shí)現(xiàn)。多個(gè)線程可以異步的做這個(gè)任務(wù)中其他事情,但是對(duì)于共享資源的訪問(wèn)只能以同步的方式操作,即一個(gè)接一個(gè)訪問(wèn)共享資源,其他資源可以并行訪問(wèn)。

  另一種實(shí)現(xiàn)多線程的方式是繼承Thread,調(diào)用的時(shí)候需要傳遞多個(gè)實(shí)例,這是多個(gè)線程,多個(gè)實(shí)例的情況,每個(gè)線程獨(dú)立處理一個(gè)實(shí)例,各個(gè)線程不能實(shí)現(xiàn)資源共享。

總結(jié)

以上是本文關(guān)于通過(guò)賣(mài)票實(shí)例理解多線程的全部?jī)?nèi)容,希望對(duì)大家有所幫助。

相關(guān)文章

  • MyBatis XML方式的基本用法之多表查詢(xún)功能的示例代碼

    MyBatis XML方式的基本用法之多表查詢(xún)功能的示例代碼

    這篇文章主要介紹了MyBatis XML方式的基本用法之多表查詢(xún)功能的示例代碼,本文通過(guò)示例文字相結(jié)合的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-07-07
  • 淺談java異常處理(父子異常的處理)

    淺談java異常處理(父子異常的處理)

    下面小編就為大家?guī)?lái)一篇淺談java異常處理(父子異常的處理)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-09-09
  • jvm-jstack常用的用法示例

    jvm-jstack常用的用法示例

    jstack 是一個(gè)常用的用于分析 Java 進(jìn)程的工具。它可以顯示 Java 進(jìn)程中所有線程狀態(tài)和堆棧信息,幫助定位 Java 進(jìn)程中的問(wèn)題,這篇文章主要介紹了jvm-jstack常用的用法示例,需要的朋友可以參考下
    2023-06-06
  • Java中String字符串轉(zhuǎn)具體對(duì)象的幾種常用方式

    Java中String字符串轉(zhuǎn)具體對(duì)象的幾種常用方式

    String對(duì)象可以用來(lái)存儲(chǔ)任何字符串類(lèi)型的數(shù)據(jù),包括HTML、XML等格式的字符串,下面這篇文章主要給大家介紹了關(guān)于JavaString字符串轉(zhuǎn)具體對(duì)象的幾種常用方式,需要的朋友可以參考下
    2024-03-03
  • 詳解Spring Data操作Redis數(shù)據(jù)庫(kù)

    詳解Spring Data操作Redis數(shù)據(jù)庫(kù)

    Redis是一種NOSQL數(shù)據(jù)庫(kù),Key-Value形式對(duì)數(shù)據(jù)進(jìn)行存儲(chǔ),其中數(shù)據(jù)可以以?xún)?nèi)存形式存在,也可以持久化到文件系統(tǒng)。Spring data對(duì)Redis進(jìn)行了很好的封裝,用起來(lái)也是十分的得心應(yīng)手,接下來(lái)通過(guò)本文給大家分享Spring Data操作Redis數(shù)據(jù)庫(kù),需要的朋友參考下
    2017-03-03
  • java如何反編譯jar包并修改class文件重新打包

    java如何反編譯jar包并修改class文件重新打包

    這篇文章主要介紹了java如何反編譯jar包并修改class文件重新打包,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • MyBatis-Plus之@TableField的用法解讀

    MyBatis-Plus之@TableField的用法解讀

    這篇文章主要介紹了MyBatis-Plus之@TableField的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Java如何判斷一個(gè)字符串是否包含某個(gè)字符串

    Java如何判斷一個(gè)字符串是否包含某個(gè)字符串

    這篇文章主要給大家介紹了關(guān)于Java如何判斷一個(gè)字符串是否包含某個(gè)字符串的相關(guān)資料,在實(shí)際編程中,經(jīng)常需要判斷一個(gè)字符串中是否包含某個(gè)子串,需要的朋友可以參考下
    2023-07-07
  • 深入學(xué)習(xí)Java單元測(cè)試(Junit+Mock+代碼覆蓋率)

    深入學(xué)習(xí)Java單元測(cè)試(Junit+Mock+代碼覆蓋率)

    在做單元測(cè)試時(shí),代碼覆蓋率常常被拿來(lái)作為衡量測(cè)試好壞的指標(biāo),甚至,用代碼覆蓋率來(lái)考核測(cè)試任務(wù)完成情況,比如,代碼覆蓋率必須達(dá)到80%或 90%。下面我們就來(lái)詳細(xì)學(xué)習(xí)下java單元測(cè)試吧
    2019-06-06
  • 解析java中super的用法分析

    解析java中super的用法分析

    本篇文章是對(duì)java中super的用法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05

最新評(píng)論