1. 程式人生 > >【Java8原始碼分析】併發包-Semaphore

【Java8原始碼分析】併發包-Semaphore

Semaphore是訊號量,它的作用是控制多個允許。

打個比方,一個博物館有容納1000人的能力(Semaphore的允許是1000),假如1500人同時來參館,只有1000人能獲得允許入館(獲得鎖),其餘的500則需排隊(阻塞),直到館內的人離開(釋放鎖)才能放人入館。

1 如何使用

public class SemaphoreDemo {

    public static void main(String[] args) {
        for (int i = 0; i < 4; i++) {
            new Thread(new SemaphoreTest()).start();
        }

    }

    static
class SemaphoreTest implements Runnable{ public static Semaphore semaphore = new Semaphore(2, true); @Override public void run() { try { semaphore.acquire(); System.out.println(Thread.currentThread() + " getting semaphore"); Thread.sleep(1000
); System.out.println(Thread.currentThread() + " realsing semaphore"); semaphore.release(); } catch (Exception e) { } } } }

程式輸出

Thread[Thread-1,5,main] getting semaphore
Thread[Thread-0,5,main] getting semaphore
Thread[Thread-0,5
,main] realsing semaphore Thread[Thread-1,5,main] realsing semaphore Thread[Thread-3,5,main] getting semaphore Thread[Thread-2,5,main] getting semaphore Thread[Thread-2,5,main] realsing semaphore Thread[Thread-3,5,main] realsing semaphore

2 原始碼分析

SemaphoreReetrantLock一樣有公平鎖與非公平鎖,ReetrantLock可以看成是Semaphore許可為1的特例,在實現中,Semaphore中的state代表可用的許可,在ReetrantLock中,state大於0代表執行緒重入的次數

2.1 非公平鎖

(1)獲取許可

final int nonfairTryAcquireShared(int acquires) {
    for (;;) {
        int available = getState();
        int remaining = available - acquires;
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}

remaining表示請求許可後的許可剩餘值,如果

  • remaining < 0,許可不足,掛起執行緒,並且新增執行緒至排隊佇列
  • remaining > 0,自旋嘗試更新state值,更新成功獲得許可

從程式碼可以看到,當一個執行緒申請許可時,無需判斷是否有執行緒在排隊佇列中,體現非公平性

(2)釋放許可

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;
    }
}

自旋採用CAS演算法更新state狀態

2.2 公平鎖

(1)獲取許可

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;
    }
}

公平鎖的機制比非公平鎖多了判斷排隊佇列是否為空,如果有其他執行緒在排隊佇列中,則該執行緒也需轉入排隊佇列,體現公平性。

3 總結

  • Semaphore是不可重入的,同一執行緒多次獲取Semaphore是會消耗許可的,例如一個Semaphore的許可為2,同一執行緒呼叫了3次acquire函式,該執行緒會被阻塞

參考

相關推薦

Java8原始碼分析NIO包-FileChannel

1 概述 Java NIO 由以下幾個核心部分組成: Buffer Channel Selectors 相關類的使用方法可以參考Java NIO 系列教程,寫的通俗易懂。 本文主要從原始碼方面分析一下Channel類。

Java8原始碼分析NIO包-Selector選擇器

1 概述 Java NIO 由以下幾個核心部分組成: Buffer Channel Selectors 相關類的使用方法可以參考Java NIO 系列教程,寫的通俗易懂。 本文主要從原始碼方面分析一下Selector選擇器。關

Java8原始碼分析發包-Semaphore

Semaphore是訊號量,它的作用是控制多個允許。 打個比方,一個博物館有容納1000人的能力(Semaphore的允許是1000),假如1500人同時來參館,只有1000人能獲得允許入館(獲得鎖),其餘的500則需排隊(阻塞),直到館內的人離開(釋

Java8原始碼分析發包-AtomicInteger

AtomicInteger類是實現了原子操作的Integer,以往對於保證int、double、float等基礎型別的運算原子性,需要採用加鎖的方式。但是為了一個簡單的運算操作採用鎖,在多執行緒競爭嚴重的情況下,會導致效能降低,所以在java1.5推出了Atom

Java8原始碼分析發包-ConcurrentHashMap(一)

一、CAS原理簡介 Java8中,ConcurrentHashMap摒棄了Segment的概念,而是啟用了一種全新的方式實現:利用CAS演算法。它沿用了HashMap的思想,底層依然由“陣列”+連結串列+紅黑樹的方式實現。 那什麼CAS演算法呢?以前採用鎖的

Java8原始碼分析集合框架-HashMap

一、HashMap的儲存結構 總共有兩種儲存類 // 1. 雜湊衝突時採用連結串列法的類,一個雜湊桶多於8個元素改為TreeNode static class Node<K,V> implements Map.Entry<K,V> /

Java8原始碼分析執行緒-Thread類的全面剖析

一、基本知識 (1)執行緒特性 每個執行緒均有優先順序 執行緒能被標記為守護執行緒 每個執行緒均分配一個name (2)建立執行緒的方法 繼承Thread類,並重現run方法 // 繼承Thread類 class PrimeThread e

Java8原始碼分析執行緒-ThreadLocal的全面剖析

一、背景 ThreadLocal類顧名思義就是,申明為ThreadLocal的變數,對於不同執行緒來說都是獨立的。 下面是一個例子: public class Test { public static void main(String[] a

go原始碼分析go原始碼之slice原始碼分析

Go 語言切片是對陣列的抽象。 Go 陣列的長度不可改變,與陣列相比切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大。 len() 和 cap() 函式     切片是可索引的,並且可以由 len() 方法獲取長度。    

go原始碼分析go原始碼之list原始碼分析

本文針對go 1.11版本,路徑src/container/list/list.go 資料結構 Element結構體 Value 前驅 後繼 // Element is an element of a linked list. type Element st

java原始碼分析Map中的hash演算法分析

全網把Map中的hash()分析的最透徹的文章,別無二家。 2018年05月09日 09:08:08 閱讀數:957 你知道HashMap中hash方法的具體實現嗎?你知道HashTable、ConcurrentHashMap中hash方法

spring原始碼分析IOC容器初始化(二)

前言:在【spring原始碼分析】IOC容器初始化(一)中已經分析了匯入bean階段,本篇接著分析bean解析階段。 1.解析bean程式呼叫鏈 同樣,先給出解析bean的程式呼叫鏈: 根據程式呼叫鏈,整理出在解析bean過程中主要涉及的類和相關方法。 2.解析bean原始碼分

NCNN原始碼分析1.基本資料型別

對於NCNN而言,核心在於網路的前向推理過程(Inference),其主要資料型別為mat,該資料型別以類的形式定義在src/mat.h中,其中包含了mat的建構函式、解構函式、常見的運算過程。 #if

Go 原始碼分析從 sort.go 看排序演算法的工程實踐

go version go1.11 darwin/amd64file: src/sort/sort.go 排序演算法有很多種類,比如快排、堆排、插入排序等。各種排序演算法各有其優劣性,在實際生產過程中用到的排序演算法(或者說 Sort 函式)通常是由幾種排序演算法組

PHP7原始碼分析如何理解PHP虛擬機器(一)

順風車運營研發團隊 李樂 1.從物理機說起 虛擬機器也是計算機,設計思想和物理機有很多相似之處; 1.1馮諾依曼體系結構 馮·諾依曼是當之無愧的數字計算機之父,當前計算機都採用的是馮諾依曼體系結構;設計思想主要包含以下幾個方面: 指令和資料不加區別混合儲存在同一個儲

Mybatis原始碼分析13-記一次PageHelper reasonable引數使用不當造成的死迴圈

問題描述及原因 使用Mybatis PageHelper外掛做了表的分頁查詢,要求查詢符合某一條件的所有記錄做處理,就寫了一個迭代器在while迴圈裡對每條記錄做處理,直到符合條件的記錄都處理完程式返回。程式碼如下 public class ReconPaymentI

Tomcat9原始碼分析元件與框架概述

1 元件與框架介紹 Server:代表整個Catalina Servlet容器,可以包含一個或多個Service Service:包含Connector和Container的集合,Service用適當的Connector接收使用者的請求,

E2LSH原始碼分析p穩定分佈LSH演算法初探

上一節,我們分析了LSH演算法的通用框架,主要是建立索引結構和查詢近似最近鄰。這一小節,我們從p穩定分佈LSH(p-Stable LSH)入手,逐漸深入學習LSH的精髓,進而靈活應用到解決大規模資料的

MyBatis原始碼分析TypeHandler解析屬性配置元素詳述及相關列舉使用高階進階

TypeHandler解析接著看一下typeHandlerElement(root.evalNode("typeHandlers"));方法,這句讀取的是<configuration>下的<typeHandlers>節點,程式碼實現為:private

proxyConfig原始碼分析proxyTargetClassexposeProxy

本文轉載自shysheng:spring proxyConfig原始碼分析 我們知道,ProxyConfig是所有產生Spring AOP代理物件的基類,它是一個配置源,主要為其AOP代理物件工廠實現類提供基本的配置屬性。 它一共包含5個屬性,本文主要就是分析這5個屬性在產生代理物件過