面試官:說說Java中的信號量?Semaphore

2021-03-02 JAVA成神寶典
前言

隨著18年開始,各個公司的面試難度,也不斷在提升,面試也不僅僅停留再ArrayList底層是如何實現的。本文就來介紹一下,我們面試經常會問的一個Semaphore,CountDownLatch、CyclicBarrier都有什麼區別。本來 就來說道說道Semaphore。

概念

Semaphore是jdk 1.5以引入的,同版本引入的還有他的兩個同胞兄弟,CountDownLatch和CyclicBarrier。位於java.util.concurrent報下,一般簡稱juc。
一個計數信號量。在概念上,信號量維持一組許可證,如果有必要,每個acquire()都會阻塞,直到許可證可用,然後才能使用它。每個release()添加許可證。

應用場景

晚上我們去願者上鉤吃烤魚,可以看到路外面站著一排排的人,都在做著等叫號,實際上也就是獲取許可。

茅坑的故事,茅坑是固定的,假設為5個,同一時刻來了10個人,還有5個人就得等待。

公司園內停車,實際上車位也是固定的,聽不下去,保安就會讓你停到其他地方(當然,社長,買不起車,所以,就沒有這種煩惱)

api接口方法描述Semaphore(int permits)創建一個 Semaphore與給定數量的許可證和非公平公平設置Semaphore(int permits, boolean fair)創建一個 Semaphore與給定數量的許可證和給定的公平設置。acquire()從該信號量獲取許可證,阻止直到可用acquire(int permits)從該信號量獲取給定數量的許可證,阻止直到所有可用release()釋放許可證release(int permits)釋放一定數量的許可證實戰

模擬一個餐廳叫號,吃飯,結算的一個場景,有4張單人桌子,來了10個客人過來吃飯的一個場景。通過信號量來實現。

package com.cxyxs.thread.fourteen;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * Description:
 * Author: 程序猿學社
 * Date:  2020/3/6 18:41
 * Modified By:
 */
public class Demo1 {
    public static void main(String[] args) {
        //4表示4張桌子
        Semaphore semaphore = new Semaphore(4);
        for (int i=0;i<10;i++) {
            final int  index=i;
            new Thread(()->{
                try {
                    //1.被服務員叫號  分發許可證
                    semaphore.acquire();
                    //2.開始吃飯
                    System.out.println(Thread.currentThread().getName()+"被服務員叫號後,準備上桌吃飯");
                    //3.吃飯中  模擬吃飯2s
                    TimeUnit.SECONDS.sleep(2);
                    //4.吃完飯,喊服務員結算
                    semaphore.release();
                    System.out.println(Thread.currentThread().getName()+"喊服務員結算!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },"客人"+index).start();
        }
    }
}

運行結果

客人0被服務員叫號後,準備上桌吃飯
客人2被服務員叫號後,準備上桌吃飯
客人1被服務員叫號後,準備上桌吃飯
客人3被服務員叫號後,準備上桌吃飯
客人1喊服務員結算!
客人6被服務員叫號後,準備上桌吃飯
客人3喊服務員結算!
客人5被服務員叫號後,準備上桌吃飯
客人4被服務員叫號後,準備上桌吃飯
客人7被服務員叫號後,準備上桌吃飯
客人2喊服務員結算!
客人0喊服務員結算!
客人4喊服務員結算!
客人5喊服務員結算!
客人9被服務員叫號後,準備上桌吃飯
客人8被服務員叫號後,準備上桌吃飯
客人6喊服務員結算!
客人7喊服務員結算!
客人9喊服務員結算!
客人8喊服務員結算!

通過上面的結果,我們可以發現,因為只有4張桌子,每次只能容納4個人,所以每次同時都有4個人得到許可。

客人1結算後,客人6就被叫號咯。

new Semaphore(4)我們應該理解了把,表示同一時刻,只能有多少個線程同時運行。

Semaphore內部也是基於AQS實現的,也就是AbstractQueuedSynchronizer的簡寫。

默認採用非公平鎖。

在實際的業務場景中,限流可能會用到。

公平鎖

   Semaphore semaphore = new Semaphore(4,true);

淺談源碼Semaphore重構方法

   public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

 private volatile int state;
  /**
     * Sets the value of synchronization state.
     * This operation has memory semantics of a {@code volatile} write.
     * @param newState the new state value
     */
    protected final void setState(int newState) {
        state = newState;
    }

acquire方法獲取許可

public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);
    }

   public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

protected int tryAcquireShared(int acquires) {
            for (;;) {
                if (hasQueuedPredecessors())
                    return -1;
                int available = getState();
                int remaining = available - acquires;
                if (remaining < 0 ||
                    compareAndSetState(available, remaining))
                    return remaining;
            }
        }

打野CAS

簡單的理解CAS是怎麼一回事。並且,他經常露臉壓線,不抓你,抓誰。通過一個簡單的小例子,理解一下CAS

  public static void main(String[] args) {
       AtomicInteger atomicInteger = new AtomicInteger(1);
        atomicInteger.compareAndSet(1,2);
        System.out.println(atomicInteger.get());
    }

 public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

release釋放許可

 public void release(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        sync.releaseShared(permits);
    }

public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

   protected final boolean tryReleaseShared(int releases) {
            for (;;) {
                int current = getState();
                int next = current + releases;
                if (next < current) // overflow
                    throw new Error("Maximum permit count exceeded");
                if (compareAndSetState(current, next))
                    return true;
            }
        }

相關焦點

  • 多線程中的信號量(Semaphore)Python每日3題(多線程專題)
    每日3題是麥叔的面試系列專題之一,每天包括初級,中級,高級難度題目各一道。[Easy] thread.join()方法的作用?思考30秒再往下翻...等待至線程中止。線程調度程序從可運行池中選擇一個線程作為當前線程時線程所處的狀態。實際上這個三狀態組合為一種,其共同點是:線程仍舊是活的(可運行的),但是當前沒有條件運行。terminated: 線程在完成執行或異常中止時進入終止狀態。[Hard] 說說多線程中的信號量(Semaphore)思考30秒再往下翻...
  • Java多線程並發工具類-信號量Semaphore對象講解
    從生活中例子中來理解Semaphore;代碼演示;總結。通過總結-理解-代碼演示-再總結這四個步驟讓大家來深刻的理解。本篇是《凱哥(凱哥Java:kagejava)並發編程學習》系列之《並發工具類》教程的第三篇:《Java多線程下信號量》。一:Semaphore是什麼?
  • Java並發編程:CountDownLatch、CyclicBarrier和Semaphore
    在java 1.5中,提供了一些非常有用的輔助類來幫助我們進行並發編程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我們就來學習一下這三個輔助類的用法。從結果可以看出,當四個線程都到達barrier狀態後,會從四個線程中選擇一個線程去執行Runnable。
  • Java並發系列 | Semaphore源碼分析
    Semaphore(信號量)是JUC包中比較常用到的一個類,它是AQS共享模式的一個應用,可以允許多個線程同時對共享資源進行操作,並且可以有效的控制並發數,利用它可以很好的實現流量控制。Semaphore提供了一個許可證的概念,可以把這個許可證看作公共汽車車票,只有成功獲取車票的人才能夠上車,並且車票是有一定數量的,不可能毫無限制的發下去,這樣就會導致公交車超載。
  • 面試官:線程順序執行,這麼多答案你都答不上來?
    前言:最近在面試過程中,發現一些面高程的朋友連怎麼實現線程順序執行都答不上來,特分享相關文章,以作科普,有收穫幫忙點個在看,感謝,助中秋快樂!本文使用了8種方法實現在多線程中讓線程按順序運行的方法,涉及到多線程中許多常用的方法,不止為了知道如何讓線程按順序運行,更是讓讀者對多線程的使用有更深刻的了解。
  • 【漫畫】面試經常問到的三個並發工具類
    如果你正準備找工作,那這篇文章就是為你量身準備的,不要想了,並發編程面試時一定會被問到的。
  • 面試 | Linux 信號量機制
    很多小夥伴在面試中會被問到一個概念——Linux 信號量機制。本篇文章將介紹一下這個與我們生態息息相關的概念。什麼是信號量?什麼是信號信號也就是信號量,那麼信號量具體是什麼呢?在 Linux 中,信號是進程間通訊的一種方式,它採用的是異步機制。
  • 分享一下面試了幾個java程式設計師後的感受
    原文:https://www.cnblogs.com/JavaArchitect/p/9032323.html 本人最近幾年一直在做java後端方面的技術面試官,而在最近兩周,又密集了面試了一些java初級和高級開發的候選人,在面試過程中,我自認為比較慎重,遇到問題回答不好的候選人,我總會再三從不同方面提問
  • 面試總結——Java高級工程師
    一、獨白之前也面試別人,現在輪到自己找工作,怎麼說呢,每個面試官的看法不一樣,面試的方式就不一樣,比如我面試別人我喜歡問項目中他用到了那些,然後針對用到的技術去問一些問題,或者說對於某些場景的一些技術實現方案是我特別喜歡問的,比如當你的接口服務數據被人截包了,你如何防止數據惡意提交?
  • 我和面試官的博弈:Java 並發編程篇
    還請大家置頂(標星)本公眾號:Java後端,第一時間接收優質博面試中問的頻率很高的一個是分布式,一個就是並發。而JUC(java.util.concurrent)裡的東西是並發編程的基石。上次的面試已經過去一段時間,在一邊努力工作的同時,我也一邊抽出時間準備 Java 並發編程的部分。今天懷著輕鬆愉快的心情,再次踏上我的大廠面試之旅。
  • 面試系列——Java工作6年面試拼多多和阿里經歷附帶面試題
    面試經歷拼多多首先說說我面試上海拼多多的經歷,我是朋友內推過去的,面試的是拼多多的商品中心部門,內推人說是拼多多技術要求最高的幾個部門之一。自己之前做過商品相關業務,業務上有些對口。接著面試官問我們公司的一些緩存架構,我們公司一般都是使用的堆內緩存 + redis 緩存(二層緩存架構方案)。然後圍繞著這個,問了數據一致性怎麼做的?有沒有做過相關壓測?指標是多少?熔斷降級有沒有做過?然後說說sentinel和hystrix的區別?
  • Semaphore裡面居然有這麼一個大坑!
    十多年後的今天,這個樂隊重新出現在我的視野中,只是李健已經不再其中。他們在樂隊的夏天的舞臺上唱了一首《青春再見》,結果被一個自稱 23 歲的胖小夥說「中年人的油膩」,被另個專業樂迷說:「四十多歲的人怎麼還在唱青春再見?」。第一期就被淘汰出局。這個怎麼就油膩了?四十多歲的人怎麼就不能唱青春再見了?男人至死都是少年你們不知道嗎?小子,他們玩音樂的時候你還不會說話呢。
  • 一位Java後臺工程師的面試經歷
    因為面試的是Java後臺開發,而且是屬於之前沒看書純粹通過面試學習面試的,可能對於剛剛工作一兩年準備換工作的Java後臺開 發更有借鑑意義吧。 創業公司:小微律政,愛旅行,遊趣科技 小微律政是法務O2O創業公司,在我面試的過程中正在衝擊A輪融資,所以承諾期權,最終給了offer,最終因為自己希望去大公司而最終拒接了offer,不過個人仍然看好他們的產品。
  • Java 線程面試題 Top 50
    在典型的Java面試中, 面試官會從線程的基本概念問起, 如:為什麼你需要使用線程, 如何創建線程,用什麼方式創建線程比較好(比如:繼承thread類還是調用Runnable接口),然後逐漸問到並發問題像在Java並發編程的過程中遇到了什麼挑戰,Java內存模型,JDK1.5引入了哪些更高階的並發工具,並發編程常用的設計模式,經典多線程問題如生產者消費者,哲學家就餐,讀寫器或者簡單的有界緩衝區問題
  • 吊打面試官系列:說說Integer緩存範圍
    Integer是基本類型int的封裝類。那麼,如何設置java.lang.Integer.IntegerCache.high的值呢?當Integer.valueOf(8);的時候,就會進入上面代碼中的if中。然後從IntegerCache中的數組cache中獲取。但是IntegerCache中的cache數組是個常量數組。
  • 因為不知道Java的CopyOnWriteArrayList,面試官讓我回去等通知
    hello,同學們,大家好,我是沉默王二,在我為數不多的面試經歷中,有一位姓馬的面試官令我印象深刻,九年過去了,我還能記得他為數不多的發量。老馬:「兄弟,ArrayList 是線程安全的嗎?」王二:「不是啊。」老馬:「那有沒有線程安全的 List?」王二:「有啊,Vector。」老馬:「還有別的嗎?」
  • 2021-Java後端工程師面試指南-(SpringBoot+SpringCloud)
    前言「文本已收錄至我的GitHub倉庫,歡迎Star:https://github.com/bin392328206/six-finger種一棵樹最好的時間是十年前,其次是現在」Tips面試指南系列,很多情況下不會去深挖細節,是小六六以被面試者的角色去回顧知識的一種方式,所以我默認大部分的東西,作為面試官的你,肯定是懂的
  • 《變態面試官》系列—Java基礎(一)
    1、面試開始我看到一個頭髮濃密,全身西服筆挺的30歲大叔面試官向我走來。不經意間掃過這位大叔腕上的百達翡麗和標著「LOTOS」字樣的眼鏡。看著對方這張好像在我長遠記憶中見過的帥氣臉龐,我突然意識到——有殺氣!1、你好,我們先來幾個簡單問題熱熱身吧,先講講Java有哪幾種基本類型?
  • java程式設計師面試遇到string題如何不涼?
    最近看到好多同學都在儲備面試知識,以備來年輕鬆應對面試官,拿到心儀offer,之前好多同學反映遇到string,都只能送給自己一首涼涼。別涼,今天小編就為大家準備了面試中常遇到的string題,讓你輕鬆愉快拿offer~首先跟大家說說如何創建string~創建字符串較簡單的方式如下String str = "Runoob";在代碼中遇到字符串常量時,這裡的值是 "Runoob"",編譯器會使用該值創建一個 String 對象。
  • Java 最常見的 200+ 面試題:面試必備
    第二:這只是經驗的高度提煉,讓那些原本就掌握了技術卻不知道怎麼表達的人,學會如何在面試中展示自己。第三:如果只是死記硬背這些面試題,只要面試官再深入問糾一下,也可對這個人有一個準確的認識,之前說的「幫人作弊」的事就存在了。