成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

淺談Java并發(fā)編程系列(八)—— LockSupport原理剖析

jeyhan / 3356人閱讀

摘要:此對(duì)象在線(xiàn)程受阻塞時(shí)被記錄,以允許監(jiān)視工具和診斷工具確定線(xiàn)程受阻塞的原因。阻塞當(dāng)前線(xiàn)程,最長(zhǎng)不超過(guò)納秒,返回條件在的基礎(chǔ)上增加了超時(shí)返回。喚醒線(xiàn)程喚醒處于阻塞狀態(tài)的線(xiàn)程。

LockSupport 用法簡(jiǎn)介

LockSupport 和 CAS 是Java并發(fā)包中很多并發(fā)工具控制機(jī)制的基礎(chǔ),它們底層其實(shí)都是依賴(lài)Unsafe實(shí)現(xiàn)。

LockSupport是用來(lái)創(chuàng)建鎖和其他同步類(lèi)的基本線(xiàn)程阻塞原語(yǔ)。LockSupport 提供park()和unpark()方法實(shí)現(xiàn)阻塞線(xiàn)程和解除線(xiàn)程阻塞,LockSupport和每個(gè)使用它的線(xiàn)程都與一個(gè)許可(permit)關(guān)聯(lián)。permit相當(dāng)于1,0的開(kāi)關(guān),默認(rèn)是0,調(diào)用一次unpark就加1變成1,調(diào)用一次park會(huì)消費(fèi)permit, 也就是將1變成0,同時(shí)park立即返回。再次調(diào)用park會(huì)變成block(因?yàn)閜ermit為0了,會(huì)阻塞在這里,直到permit變?yōu)?), 這時(shí)調(diào)用unpark會(huì)把permit置為1。每個(gè)線(xiàn)程都有一個(gè)相關(guān)的permit, permit最多只有一個(gè),重復(fù)調(diào)用unpark也不會(huì)積累。

park()和unpark()不會(huì)有 “Thread.suspend和Thread.resume所可能引發(fā)的死鎖” 問(wèn)題,由于許可的存在,調(diào)用 park 的線(xiàn)程和另一個(gè)試圖將其 unpark 的線(xiàn)程之間的競(jìng)爭(zhēng)將保持活性。

如果調(diào)用線(xiàn)程被中斷,則park方法會(huì)返回。同時(shí)park也擁有可以設(shè)置超時(shí)時(shí)間的版本。

需要特別注意的一點(diǎn):park 方法還可以在其他任何時(shí)間“毫無(wú)理由”地返回,因此通常必須在重新檢查返回條件的循環(huán)里調(diào)用此方法。從這個(gè)意義上說(shuō),park 是“忙碌等待”的一種優(yōu)化,它不會(huì)浪費(fèi)這么多的時(shí)間進(jìn)行自旋,但是必須將它與 unpark 配對(duì)使用才更高效。

三種形式的 park 還各自支持一個(gè) blocker 對(duì)象參數(shù)。此對(duì)象在線(xiàn)程受阻塞時(shí)被記錄,以允許監(jiān)視工具和診斷工具確定線(xiàn)程受阻塞的原因。(這樣的工具可以使用方法 getBlocker(java.lang.Thread) 訪(fǎng)問(wèn) blocker。)建議最好使用這些形式,而不是不帶此參數(shù)的原始形式。在鎖實(shí)現(xiàn)中提供的作為 blocker 的普通參數(shù)是 this。
看下線(xiàn)程dump的結(jié)果來(lái)理解blocker的作用。

從線(xiàn)程dump結(jié)果可以看出:
有blocker的可以傳遞給開(kāi)發(fā)人員更多的現(xiàn)場(chǎng)信息,可以查看到當(dāng)前線(xiàn)程的阻塞對(duì)象,方便定位問(wèn)題。所以java6新增加帶blocker入?yún)⒌南盗衟ark方法,替代原有的park方法。

看一個(gè)Java docs中的示例用法:一個(gè)先進(jìn)先出非重入鎖類(lèi)的框架

class FIFOMutex {
    private final AtomicBoolean locked = new AtomicBoolean(false);
    private final Queue waiters
      = new ConcurrentLinkedQueue();
 
    public void lock() {
      boolean wasInterrupted = false;
      Thread current = Thread.currentThread();
      waiters.add(current);
 
      // Block while not first in queue or cannot acquire lock
      while (waiters.peek() != current ||
             !locked.compareAndSet(false, true)) {
        LockSupport.park(this);
        if (Thread.interrupted()) // ignore interrupts while waiting
          wasInterrupted = true;
      }

      waiters.remove();
      if (wasInterrupted)          // reassert interrupt status on exit
        current.interrupt();
    }
 
    public void unlock() {
      locked.set(false);
      LockSupport.unpark(waiters.peek());
    }
  }}
LockSupport 源碼解讀

LockSupport中主要的兩個(gè)成員變量:

// Hotspot implementation via intrinsics API
    private static final sun.misc.Unsafe UNSAFE;
    private static final long parkBlockerOffset;

unsafe:全名sun.misc.Unsafe可以直接操控內(nèi)存,被JDK廣泛用于自己的包中,如java.nio和java.util.concurrent。但是不建議在生產(chǎn)環(huán)境中使用這個(gè)類(lèi)。因?yàn)檫@個(gè)API十分不安全、不輕便、而且不穩(wěn)定。
LockSupport的方法底層都是調(diào)用Unsafe的方法實(shí)現(xiàn)。

再來(lái)看parkBlockerOffset:
parkBlocker就是第一部分說(shuō)到的用于記錄線(xiàn)程被誰(shuí)阻塞的,用于線(xiàn)程監(jiān)控和分析工具來(lái)定位原因的,可以通過(guò)LockSupport的getBlocker獲取到阻塞的對(duì)象。

 static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class tk = Thread.class;
            parkBlockerOffset = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("parkBlocker"));
        } catch (Exception ex) { throw new Error(ex); }
 }

從這個(gè)靜態(tài)語(yǔ)句塊可以看的出來(lái),先是通過(guò)反射機(jī)制獲取Thread類(lèi)的parkBlocker字段對(duì)象。然后通過(guò)sun.misc.Unsafe對(duì)象的objectFieldOffset方法獲取到parkBlocker在內(nèi)存里的偏移量,parkBlockerOffset的值就是這么來(lái)的.

JVM的實(shí)現(xiàn)可以自由選擇如何實(shí)現(xiàn)Java對(duì)象的“布局”,也就是在內(nèi)存里Java對(duì)象的各個(gè)部分放在哪里,包括對(duì)象的實(shí)例字段和一些元數(shù)據(jù)之類(lèi)。 sun.misc.Unsafe里關(guān)于對(duì)象字段訪(fǎng)問(wèn)的方法把對(duì)象布局抽象出來(lái),它提供了objectFieldOffset()方法用于獲取某個(gè)字段相對(duì) Java對(duì)象的“起始地址”的偏移量,也提供了getInt、getLong、getObject之類(lèi)的方法可以使用前面獲取的偏移量來(lái)訪(fǎng)問(wèn)某個(gè)Java 對(duì)象的某個(gè)字段。

為什么要用偏移量來(lái)獲取對(duì)象?干嗎不要直接寫(xiě)個(gè)get,set方法。多簡(jiǎn)單?
仔細(xì)想想就能明白,這個(gè)parkBlocker就是在線(xiàn)程處于阻塞的情況下才會(huì)被賦值。線(xiàn)程都已經(jīng)阻塞了,如果不通過(guò)這種內(nèi)存的方法,而是直接調(diào)用線(xiàn)程內(nèi)的方法,線(xiàn)程是不會(huì)回應(yīng)調(diào)用的。

2.LockSupport的方法:

可以看到,LockSupport中主要是park和unpark方法以及設(shè)置和讀取parkBlocker方法。

 private static void setBlocker(Thread t, Object arg) {
        // Even though volatile, hotspot doesn"t need a write barrier here.
        UNSAFE.putObject(t, parkBlockerOffset, arg);
  }

對(duì)給定線(xiàn)程t的parkBlocker賦值。

    public static Object getBlocker(Thread t) {
        if (t == null)
            throw new NullPointerException();
        return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
    }
  

從線(xiàn)程t中獲取它的parkBlocker對(duì)象,即返回的是阻塞線(xiàn)程t的Blocker對(duì)象。

接下來(lái)主查兩類(lèi)方法,一類(lèi)是阻塞park方法,一類(lèi)是解除阻塞unpark方法

阻塞線(xiàn)程

park()

public static void park() {
        UNSAFE.park(false, 0L);
}

調(diào)用native方法阻塞當(dāng)前線(xiàn)程。

parkNanos(long nanos)

public static void parkNanos(long nanos) {
        if (nanos > 0)
            UNSAFE.park(false, nanos);
}

阻塞當(dāng)前線(xiàn)程,最長(zhǎng)不超過(guò)nanos納秒,返回條件在park()的基礎(chǔ)上增加了超時(shí)返回。

parkUntil(long deadline)

public static void parkUntil(long deadline) {
  UNSAFE.park(true, deadline);
}

阻塞當(dāng)前線(xiàn)程,知道deadline時(shí)間(deadline - 毫秒數(shù))。

JDK1.6引入這三個(gè)方法對(duì)應(yīng)的擁有Blocker版本。

park(Object blocker)

public static void park(Object blocker) {
  Thread t = Thread.currentThread();
  setBlocker(t, blocker);
  UNSAFE.park(false, 0L);
  setBlocker(t, null);
}

1) 記錄當(dāng)前線(xiàn)程等待的對(duì)象(阻塞對(duì)象);
2) 阻塞當(dāng)前線(xiàn)程;
3) 當(dāng)前線(xiàn)程等待對(duì)象置為null。

parkNanos(Object blocker, long nanos)

public static void parkNanos(Object blocker, long nanos) {
  if (nanos > 0) {
      Thread t = Thread.currentThread();
      setBlocker(t, blocker);
      UNSAFE.park(false, nanos);
      setBlocker(t, null);
  }
}

阻塞當(dāng)前線(xiàn)程,最長(zhǎng)等待時(shí)間不超過(guò)nanos毫秒,同樣,在阻塞當(dāng)前線(xiàn)程的時(shí)候做了記錄當(dāng)前線(xiàn)程等待的對(duì)象操作。

parkUntil(Object blocker, long deadline)

public static void parkUntil(Object blocker, long deadline) {
  Thread t = Thread.currentThread();
  setBlocker(t, blocker);
  UNSAFE.park(true, deadline);
  setBlocker(t, null);
}

阻塞當(dāng)前線(xiàn)程直到deadline時(shí)間,相同的,也做了阻塞前記錄當(dāng)前線(xiàn)程等待對(duì)象的操作。

喚醒線(xiàn)程

unpark(Thread thread)

public static void unpark(Thread thread) {
  if (thread != null)
      UNSAFE.unpark(thread);
}

喚醒處于阻塞狀態(tài)的線(xiàn)程Thread。

參考:
http://tool.oschina.net/apido...
http://ifeve.com/locksuppor-s...
http://www.jianshu.com/p/ceb8...
http://15838341661-139-com.it...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/66694.html

相關(guān)文章

  • 后臺(tái)開(kāi)發(fā)常問(wèn)面試題集錦(問(wèn)題搬運(yùn)工,附鏈接)

    摘要:基礎(chǔ)問(wèn)題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線(xiàn)抽象關(guān)鍵字修飾符知識(shí)點(diǎn)總結(jié)必看篇中的關(guān)鍵字解析回調(diào)機(jī)制解讀抽象類(lèi)與三大特征時(shí)間和時(shí)間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類(lèi)對(duì)象鎖和類(lèi)鎖的區(qū)別,,優(yōu)缺點(diǎn)及比較提高篇八詳解內(nèi)部類(lèi)單例模式和 Java基礎(chǔ)問(wèn)題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...

    spacewander 評(píng)論0 收藏0
  • 后臺(tái)開(kāi)發(fā)常問(wèn)面試題集錦(問(wèn)題搬運(yùn)工,附鏈接)

    摘要:基礎(chǔ)問(wèn)題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線(xiàn)抽象關(guān)鍵字修飾符知識(shí)點(diǎn)總結(jié)必看篇中的關(guān)鍵字解析回調(diào)機(jī)制解讀抽象類(lèi)與三大特征時(shí)間和時(shí)間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類(lèi)對(duì)象鎖和類(lèi)鎖的區(qū)別,,優(yōu)缺點(diǎn)及比較提高篇八詳解內(nèi)部類(lèi)單例模式和 Java基礎(chǔ)問(wèn)題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...

    xfee 評(píng)論0 收藏0
  • 后臺(tái)開(kāi)發(fā)常問(wèn)面試題集錦(問(wèn)題搬運(yùn)工,附鏈接)

    摘要:基礎(chǔ)問(wèn)題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線(xiàn)抽象關(guān)鍵字修飾符知識(shí)點(diǎn)總結(jié)必看篇中的關(guān)鍵字解析回調(diào)機(jī)制解讀抽象類(lèi)與三大特征時(shí)間和時(shí)間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類(lèi)對(duì)象鎖和類(lèi)鎖的區(qū)別,,優(yōu)缺點(diǎn)及比較提高篇八詳解內(nèi)部類(lèi)單例模式和 Java基礎(chǔ)問(wèn)題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...

    makeFoxPlay 評(píng)論0 收藏0
  • Java并發(fā)編程之旅總覽

    摘要:線(xiàn)程安全的概念什么時(shí)候線(xiàn)程不安全怎樣做到線(xiàn)程安全怎么擴(kuò)展線(xiàn)程安全的類(lèi)對(duì)線(xiàn)程安全的支持對(duì)線(xiàn)程安全支持有哪些中的線(xiàn)程池的使用與中線(xiàn)程池的生命周期與線(xiàn)程中斷中的鎖中常見(jiàn)死鎖與活鎖的實(shí)例線(xiàn)程同步機(jī)制顯示鎖使用與原理原理剖析原理中的與原理偏向鎖狀態(tài) showImg(https://segmentfault.com/img/bVblUE9?w=1354&h=1660); 線(xiàn)程安全的概念 showI...

    Harpsichord1207 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<