日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

自旋鎖

自旋鎖是指當一個線程嘗試獲取某個鎖時,如果該鎖已被其他線程占用,就一直循環檢測鎖是否被釋放,而不是進入線程掛起或睡眠狀態。

自旋鎖適用于鎖保護的臨界區很小的情況,臨界區很小的話,鎖占用的時間就很短。

簡單的實現

import JAVA.util.concurrent.atomic.AtomicReference;

public class SpinLock {

private AtomicReference<Thread> owner = new AtomicReference<Thread>();

public void lock() {

Thread currentThread = Thread.currentThread();

// 如果鎖未被占用,則設置當前線程為鎖的擁有者

while (!owner.compareAndSet(null, currentThread)) {

}

}

public void unlock() {

Thread currentThread = Thread.currentThread();

// 只有鎖的擁有者才能釋放鎖

owner.compareAndSet(currentThread, null);

}

}

SimpleSpinLock里有一個owner屬性持有鎖當前擁有者的線程的引用,如果該引用為null,則表示鎖未被占用,不為null則被占用。

這里用AtomicReference是為了使用它的原子性的compareAndSet方法(CAS操作),解決了多線程并發操作導致數據不一致的問題,確保其他線程可以看到鎖的真實狀態。

缺點

  1. CAS操作需要硬件的配合;
  2. 保證各個CPU的緩存(L1、L2、L3、跨CPU Socket、主存)的數據一致性,通訊開銷很大,在多處理器系統上更嚴重;
  3. 沒法保證公平性,不保證等待進程/線程按照FIFO順序獲得鎖。

排隊自旋鎖(Ticket Lock)

Ticket Lock 是為了解決上面的公平性問題,類似于現實中銀行柜臺的排隊叫號:鎖擁有一個服務號,表示正在服務的線程,還有一個排隊號;每個線程嘗試獲取鎖之前先拿一個排隊號,然后不斷輪詢鎖的當前服務號是否是自己的排隊號,如果是,則表示自己擁有了鎖,不是則繼續輪詢。

當線程釋放鎖時,將服務號加1,這樣下一個線程看到這個變化,就退出自旋。

簡單的實現

import java.util.concurrent.atomic.AtomicInteger;

public class TicketLock {

private AtomicInteger serviceNum = new AtomicInteger(); // 服務號

private AtomicInteger ticketNum = new AtomicInteger(); // 排隊號

public int lock() {

// 首先原子性地獲得一個排隊號

int myTicketNum = ticketNum.getAndIncrement();

// 只要當前服務號不是自己的就不斷輪詢

while (serviceNum.get() != myTicketNum) {

}

return myTicketNum;

}

public void unlock(int myTicket) {

// 只有當前線程擁有者才能釋放鎖

int next = myTicket + 1;

serviceNum.compareAndSet(myTicket, next);

}

}

缺點

Ticket Lock 雖然解決了公平性的問題,但是多處理器系統上,每個進程/線程占用的處理器都在讀寫同一個變量serviceNum ,每次讀寫操作都必須在多個處理器緩存之間進行緩存同步,這會導致繁重的系統總線和內存的流量,大大降低系統整體的性能。

下面介紹的CLH鎖和MCS鎖都是為了解決這個問題的。

MCS 來自于其發明人名字的首字母: John Mellor-Crummey和Michael Scott。

CLH的發明人是:Craig,Landin and Hagersten。

MCS鎖

MCS Spinlock 是一種基于鏈表的可擴展、高性能、公平的自旋鎖,申請線程只在本地變量上自旋,直接前驅負責通知其結束自旋,從而極大地減少了不必要的處理器緩存同步的次數,降低了總線和內存的開銷。

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

public class MCSLock {

public static class MCSNode {

volatile MCSNode next;

volatile boolean isBlock = true; // 默認是在等待鎖

}

volatile MCSNode queue;// 指向最后一個申請鎖的MCSNode

private static final AtomicReferenceFieldUpdater UPDATER = AtomicReferenceFieldUpdater

.newUpdater(MCSLock.class, MCSNode.class, "queue");

public void lock(MCSNode currentThread) {

MCSNode predecessor = UPDATER.getAndSet(this, currentThread);// step 1

if (predecessor != null) {

predecessor.next = currentThread;// step 2

while (currentThread.isBlock) {// step 3

}

}else { // 只有一個線程在使用鎖,沒有前驅來通知它,所以得自己標記自己為非阻塞

currentThread. isBlock = false;

}

}

public void unlock(MCSNode currentThread) {

if (currentThread.isBlock) {// 鎖擁有者進行釋放鎖才有意義

return;

}

if (currentThread.next == null) {// 檢查是否有人排在自己后面

if (UPDATER.compareAndSet(this, currentThread, null)) {// step 4

// compareAndSet返回true表示確實沒有人排在自己后面

return;

} else {

// 突然有人排在自己后面了,可能還不知道是誰,下面是等待后續者

// 這里之所以要忙等是因為:step 1執行完后,step 2可能還沒執行完

while (currentThread.next == null) { // step 5

}

}

}

currentThread.next.isBlock = false;

currentThread.next = null;// for GC

}

}

CLH鎖

CLH鎖也是一種基于鏈表的可擴展、高性能、公平的自旋鎖,申請線程只在本地變量上自旋,它不斷輪詢前驅的狀態,如果發現前驅釋放了鎖就結束自旋。

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

public class CLHLock {

public static class CLHNode {

private volatile boolean isLocked = true; // 默認是在等待鎖

}

@SuppressWarnings("unused" )

private volatile CLHNode tail ;

private static final AtomicReferenceFieldUpdater<CLHLock, CLHNode> UPDATER = AtomicReferenceFieldUpdater

. newUpdater(CLHLock.class, CLHNode .class , "tail" );

public void lock(CLHNode currentThread) {

CLHNode preNode = UPDATER.getAndSet( this, currentThread);

if(preNode != null) {//已有線程占用了鎖,進入自旋

while(preNode.isLocked ) {

}

}

}

public void unlock(CLHNode currentThread) {

// 如果隊列里只有當前線程,則釋放對當前線程的引用(for GC)。

if (!UPDATER .compareAndSet(this, currentThread, null)) {

// 還有后續線程

currentThread. isLocked = false ;// 改變狀態,讓后續線程結束自旋

}

}

}

CLH鎖 與 MCS鎖 的比較

下圖是CLH鎖和MCS鎖隊列圖示:

自旋鎖、排隊自旋鎖、MCS鎖、CLH鎖

差異:

  1. 從代碼實現來看,CLH比MCS要簡單得多。
  2. 從自旋的條件來看,CLH是在前驅節點的屬性上自旋,而MCS是在本地屬性變量上自旋。
  3. 從鏈表隊列來看,CLH的隊列是隱式的,CLHNode并不實際持有下一個節點;MCS的隊列是物理存在的。
  4. CLH鎖釋放時只需要改變自己的屬性,MCS鎖釋放則需要改變后繼節點的屬性。
  5. CLH鎖可以更容易地去實現“取消 (cancellation)”和“超時”功能,

注意:這里實現的鎖都是獨占的,且不能重入的。

分享到:
標簽:自旋
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定