自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

三種方法模擬雙線(xiàn)程搶票

開(kāi)發(fā) 前端
在多線(xiàn)程編程中,資源競(jìng)爭(zhēng)是一個(gè)常見(jiàn)的問(wèn)題。資源競(jìng)爭(zhēng)發(fā)生在多個(gè)線(xiàn)程試圖同時(shí)訪問(wèn)或修改共享資源時(shí),可能導(dǎo)致數(shù)據(jù)不一致或其他并發(fā)問(wèn)題。在模擬兩個(gè)線(xiàn)程搶票的場(chǎng)景中,我們需要考慮如何公平地分配票,并確保每個(gè)線(xiàn)程都有機(jī)會(huì)成功獲取票。

前言

在多線(xiàn)程編程中,資源競(jìng)爭(zhēng)是一個(gè)常見(jiàn)的問(wèn)題。資源競(jìng)爭(zhēng)發(fā)生在多個(gè)線(xiàn)程試圖同時(shí)訪問(wèn)或修改共享資源時(shí),可能導(dǎo)致數(shù)據(jù)不一致或其他并發(fā)問(wèn)題。在模擬兩個(gè)線(xiàn)程搶票的場(chǎng)景中,我們需要考慮如何公平地分配票,并確保每個(gè)線(xiàn)程都有機(jī)會(huì)成功獲取票。

本篇文章將通過(guò)三種方式來(lái)模擬兩個(gè)線(xiàn)程搶票的過(guò)程,以展示不同的并發(fā)控制策略。

這三種方式包括:

  • 使用 Synchronized 來(lái)確保一次只有一個(gè)線(xiàn)程可以訪問(wèn)票資源。
  • 使用 ReentrantLock 來(lái)實(shí)現(xiàn)線(xiàn)程間的協(xié)調(diào)。
  • 使用 Semaphore 來(lái)限制同時(shí)訪問(wèn)票的線(xiàn)程數(shù)量。

通過(guò)比較這三種方式,我們可以深入了解并發(fā)控制的不同實(shí)現(xiàn)方式及其優(yōu)缺點(diǎn)。在實(shí)際應(yīng)用中,需要根據(jù)具體場(chǎng)景和需求選擇合適的并發(fā)控制策略。

此外,為了更直觀地展示搶票過(guò)程,我們將使用代碼來(lái)描述每種方式的實(shí)現(xiàn)邏輯。

一、Synchronized

含義:Synchronized 是 Java 中的一個(gè)關(guān)鍵字,用于實(shí)現(xiàn)線(xiàn)程同步。當(dāng)一個(gè)方法或代碼塊被 Synchronized 修飾時(shí),同一時(shí)間只能有一個(gè)線(xiàn)程可以執(zhí)行這個(gè)方法或代碼塊。

圖片圖片

代碼如下:

static class TicketSystemBySynchronized {
  private int tickets = 100;


  public void sellTicket() {
    while (tickets > 0) { //還有票時(shí)進(jìn)行循環(huán)
      synchronized (this) {
        try {
          if (tickets > 0)
            System.out.println(Thread.currentThread().getName()
                + "賣(mài)出一張票,剩余票數(shù):" + --tickets);
          Thread.sleep(200); //模擬售票
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }
}

這個(gè)類(lèi)中有一個(gè)私有的整型變量 tickets,表示票的總數(shù),初始值為 100。

類(lèi)中有一個(gè)公共方法 sellTicket(),這個(gè)方法模擬售票過(guò)程。當(dāng)還有票(tickets > 0)時(shí),會(huì)進(jìn)入一個(gè) while 循環(huán)。在循環(huán)中,首先通過(guò) synchronized (this) 對(duì)當(dāng)前對(duì)象進(jìn)行同步,保證同一時(shí)間只有一個(gè)線(xiàn)程可以執(zhí)行以下代碼塊。

在同步代碼塊中,首先檢查票的數(shù)量是否大于0。如果是,則輸出當(dāng)前線(xiàn)程的名稱(chēng)以及售出的票數(shù)和剩余票數(shù)。然后,通過(guò) --tickets 操作將票的數(shù)量減1。

接下來(lái),線(xiàn)程休眠 200 毫秒(模擬售票過(guò)程)。休眠結(jié)束后,循環(huán)繼續(xù)執(zhí)行,直到票的數(shù)量為 0。

二、ReentrantLock

含義:ReentrantLock,也稱(chēng)為可重入鎖,是一種遞歸無(wú)阻塞的同步機(jī)制。它可以等同于 synchronized 的使用,但是 ReentrantLock 提供了比 synchronized 更強(qiáng)大、靈活的鎖機(jī)制,可以減少死鎖發(fā)生的概率。

圖片圖片

代碼如下:

static class TicketSystemByReentrantLock {
  private int tickets = 100;


  private final ReentrantLock lock = new ReentrantLock(); //定義鎖


  public void sellTicket() {
    while (tickets > 0) {
      lock.lock(); //上鎖
      try {
        Thread.sleep(200); //模擬售票
        if (tickets > 0)
          System.out.println(Thread.currentThread().getName()
              + "賣(mài)出一張票,剩余票數(shù):" + --tickets);
      } catch (InterruptedException e) {
        e.printStackTrace();
      } finally {
        lock.unlock(); //解鎖
      }
    }
  }
}

這個(gè)類(lèi)中有一個(gè)私有的整型變量 tickets,表示票的總數(shù),初始值為 100。另外定義了一個(gè)私有的 final 類(lèi)型的 ReentrantLock 對(duì)象 lock,這個(gè)對(duì)象用于控制對(duì)共享資源的訪問(wèn)。

類(lèi)中有一個(gè)公共方法 sellTicket(),這個(gè)方法模擬售票過(guò)程。當(dāng)還有票(tickets > 0)時(shí),會(huì)進(jìn)入一個(gè) while 循環(huán)。在循環(huán)中,首先通過(guò) lock.lock() 獲取鎖,保證同一時(shí)間只有一個(gè)線(xiàn)程可以執(zhí)行以下代碼塊。

在鎖保護(hù)的代碼塊中,首先線(xiàn)程休眠 200 毫秒(模擬售票過(guò)程)。然后檢查票的數(shù)量是否大于 0。如果是,則輸出當(dāng)前線(xiàn)程的名稱(chēng)以及售出的票數(shù)和剩余票數(shù)。然后,通過(guò) --tickets 操作將票的數(shù)量減 1。

最后,都會(huì)通過(guò) lock.unlock() 釋放鎖。防止死鎖!

三、Semaphore

含義:Semaphore 是一種計(jì)數(shù)信號(hào)量,用于管理一組資源。它是一種在多線(xiàn)程環(huán)境下使用的設(shè)施,該設(shè)施負(fù)責(zé)協(xié)調(diào)各個(gè)線(xiàn)程,以保證它們能夠正確、合理地使用公共資源。Semaphore 內(nèi)部基于 AQS(Abstract Queued Synchronizer)的共享模式,相當(dāng)于給線(xiàn)程規(guī)定一個(gè)量從而控制允許活動(dòng)的線(xiàn)程數(shù)。

圖片圖片

代碼如下:

static class TicketSystemBySemaphore {
  private final Semaphore semaphore;


  public TicketSystemBySemaphore() {
    this.semaphore = new Semaphore(100); //總共100張票
  }


  public void sellTicket() {
    int i = semaphore.availablePermits(); //返回此信號(hào)量中當(dāng)前可用的許可證數(shù)


    while (i > 0) {
      try {
        Thread.sleep(200);
        semaphore.acquire(); // 獲取信號(hào)量,如果信號(hào)量為0,線(xiàn)程將阻塞等待
        System.out.println(
            Thread.currentThread().getName() + "賣(mài)出一張票,剩余票數(shù):" + --i);
      } catch (InterruptedException e) {
        throw new RuntimeException(e);
      } finally {
        semaphore.release(); // 釋放信號(hào)量,允許其他線(xiàn)程獲取信號(hào)量
      }
    }
  }
}

Semaphore 是一個(gè)計(jì)數(shù)信號(hào)量,用于控制資源的并發(fā)訪問(wèn)。在構(gòu)造函數(shù)中,初始化了這個(gè) Semaphore,設(shè)置總的可用票數(shù)為 100。

sellTicket() 方法模擬售票過(guò)程。首先獲取當(dāng)前可用的票數(shù),然后進(jìn)入一個(gè) while 循環(huán),只要還有可用的票,就會(huì)嘗試獲取一個(gè)票。如果當(dāng)前沒(méi)有可用的票,線(xiàn)程將會(huì)阻塞等待。一旦獲取了票,就輸出售出的信息。最后釋放信號(hào)量。

四、抽象工廠模式優(yōu)化

含義:抽象工廠模式是一種創(chuàng)建型設(shè)計(jì)模式,它為創(chuàng)建一系列相關(guān)或互相依賴(lài)的對(duì)象提供了一種最佳解決方案。這種類(lèi)型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式。

圖片圖片

因?yàn)橐獙?duì)三種實(shí)現(xiàn)類(lèi)型的代碼進(jìn)行測(cè)試,不想多寫(xiě) if...else... 的代碼,不想每次指定創(chuàng)建的對(duì)象,也為了防止以后有更多實(shí)現(xiàn)方法的不方便。提高代碼的可維護(hù)性和可擴(kuò)展性。

所以這里采用抽象工廠模式來(lái)進(jìn)行優(yōu)化。

代碼如下:

首先實(shí)現(xiàn)一個(gè)接口類(lèi):

public interface TicketSystem {
    void sellTicket();
}

因?yàn)槿齻€(gè)模擬實(shí)現(xiàn)中都定義了 sellTicket 這個(gè)方法,所以在接口類(lèi)里面定義一個(gè)方法,然后由實(shí)現(xiàn)類(lèi)去重寫(xiě)該方法。

接下來(lái)實(shí)現(xiàn)靜態(tài)工廠類(lèi):

static class CodeSandboxFactory {
  static TicketSystem newInstance(String type) {
    switch (type) {
      case "Synchronized":
        return new TicketSystemBySynchronized();
      case "ReentrantLock":
        return new TicketSystemByReentrantLock();
      case "Semaphore":
      default:
        return new TicketSystemBySemaphore();
    }
  }
}

這個(gè) CodeSandboxFactory 類(lèi)是一個(gè)靜態(tài)工廠類(lèi),用于創(chuàng)建TicketSystem對(duì)象的不同實(shí)例。它接受一個(gè)字符串參數(shù) type,根據(jù)該參數(shù)的值決定創(chuàng)建哪種類(lèi)型的TicketSystem 對(duì)象。

  • 如果type參數(shù)的值為"Synchronized",則返回一個(gè)新的 TicketSystemBySynchronized對(duì)象;
  • 如果type參數(shù)的值為"ReentrantLock",則返回一個(gè)新的 TicketSystemByReentrantLock 對(duì)象;
  • 如果type參數(shù)的值為"Semaphore",則返回一個(gè)新的 TicketSystemBySemaphore對(duì)象;
  • 如果type參數(shù)的值不是以上三種之一,則默認(rèn)返回一個(gè)新的TicketSystemBySemaphore 對(duì)象。

這種設(shè)計(jì)使得客戶(hù)端代碼可以方便地通過(guò)傳遞不同的類(lèi)型字符串來(lái)獲取不同類(lèi)型的 TicketSystem 對(duì)象,而不需要關(guān)心這些對(duì)象的實(shí)際創(chuàng)建過(guò)程。

這有助于降低客戶(hù)端代碼與具體實(shí)現(xiàn)之間的耦合度,提高代碼的可維護(hù)性和可擴(kuò)展性。

五、整體代碼 

代碼如下:

public class ThreadsGrabTickets {
  public static void main(String[] args) {
    TicketSystem system = CodeSandboxFactory.newInstance("Synchronized");
    //        TicketSystem system =
    //        CodeSandboxFactory.newInstance("ReentrantLock"); TicketSystem
    //        system = CodeSandboxFactory.newInstance("Semaphore");


    new Thread(system::sellTicket, "線(xiàn)程1").start();
    new Thread(system::sellTicket, "線(xiàn)程2").start();
  }


  static class CodeSandboxFactory {
    static TicketSystem newInstance(String type) {
      switch (type) {
        case "Synchronized":
          return new TicketSystemBySynchronized();
        case "ReentrantLock":
          return new TicketSystemByReentrantLock();
        case "Semaphore":
        default:
          return new TicketSystemBySemaphore();
      }
    }
  }


  static class TicketSystemBySynchronized implements TicketSystem {
    private int tickets = 100;


    @Override
    public void sellTicket() {
      while (tickets > 0) {
        synchronized (this) {
          try {
            if (tickets > 0)
              System.out.println(Thread.currentThread().getName()
                  + "賣(mài)出一張票,剩余票數(shù):" + --tickets);
            Thread.sleep(200);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    }
  }


  static class TicketSystemByReentrantLock implements TicketSystem {
    private int tickets = 100;


    private final ReentrantLock lock = new ReentrantLock(); //定義鎖


    @Override
    public void sellTicket() {
      while (tickets > 0) {
        lock.lock(); //上鎖
        try {
          Thread.sleep(200); //模擬售票
          if (tickets > 0)
            System.out.println(Thread.currentThread().getName()
                + "賣(mài)出一張票,剩余票數(shù):" + --tickets);
        } catch (InterruptedException e) {
          e.printStackTrace();
        } finally {
          lock.unlock(); //解鎖
        }
      }
    }
  }


  static class TicketSystemBySemaphore implements TicketSystem {
    private final Semaphore semaphore;


    public TicketSystemBySemaphore() {
      this.semaphore = new Semaphore(100); //總共100張票
    }


    @Override
    public void sellTicket() {
      int i = semaphore.availablePermits(); //返回此信號(hào)量中當(dāng)前可用的許可證數(shù)


      while (i > 0) {
        try {
          Thread.sleep(200);
          semaphore.acquire(); // 獲取信號(hào)量,如果信號(hào)量為0,線(xiàn)程將阻塞等待
          System.out.println(Thread.currentThread().getName()
              + "賣(mài)出一張票,剩余票數(shù):" + --i);
        } catch (InterruptedException e) {
          throw new RuntimeException(e);
        } finally {
          semaphore.release(); // 釋放信號(hào)量,允許其他線(xiàn)程獲取信號(hào)量
        }
      }
    }
  }
}

六、總結(jié)

本文通過(guò)模擬兩個(gè)線(xiàn)程搶票的場(chǎng)景,展示了三種不同的并發(fā)控制策略:使用 Synchronized、ReentrantLock 和 Semaphore。

通過(guò)比較這三種方式,我們可以深入了解并發(fā)控制的不同實(shí)現(xiàn)方式。

在實(shí)際應(yīng)用中,需要根據(jù)具體場(chǎng)景和需求選擇合適的并發(fā)控制策略。

責(zé)任編輯:武曉燕 來(lái)源: 一安未來(lái)
相關(guān)推薦

2022-07-07 00:33:34

Java線(xiàn)程同步

2023-08-03 16:02:24

Objectwaitnotify

2009-06-29 18:18:53

Java多線(xiàn)程向線(xiàn)程傳遞數(shù)據(jù)

2009-07-08 12:56:32

編寫(xiě)Servlet

2013-01-04 15:47:54

Android開(kāi)發(fā)平鋪UI設(shè)計(jì)

2011-06-10 10:43:12

Ubuntu應(yīng)用安裝

2009-06-23 10:45:18

Hibernate支持

2009-12-11 18:49:39

預(yù)算編制博科資訊

2022-07-13 16:06:16

Python參數(shù)代碼

2024-11-15 07:00:00

Python發(fā)送郵件

2011-04-18 15:32:45

游戲測(cè)試測(cè)試方法軟件測(cè)試

2023-08-14 17:58:13

RequestHTTP請(qǐng)求

2010-09-14 15:10:49

CSS注釋

2020-06-17 10:52:00

DDoS攻擊網(wǎng)絡(luò)攻擊網(wǎng)絡(luò)安全

2016-10-12 13:53:38

JavaByteBufferRandomAcces

2010-09-08 13:29:48

CSS

2023-02-21 14:58:12

間序列周期數(shù)據(jù)集

2010-11-16 16:11:28

Oracle身份驗(yàn)證

2024-08-28 11:10:53

2022-05-30 07:07:35

Java監(jiān)聽(tīng)文件Java 8
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)