日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

聊聊高并发(十七)解析java.util.concurrent各个组件(一) 了解sun.misc.Unsafe类

發布時間:2024/1/17 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 聊聊高并发(十七)解析java.util.concurrent各个组件(一) 了解sun.misc.Unsafe类 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

了解了并發編程中鎖的基本原理之后,接下來看看Java是如何利用這些原理來實現各種鎖,原子變量,同步組件的。在開始分析java.util.concurrent的源代碼直接,首先要了解的就是sun.misc.Unsafe類,這個類可以說的java并發包的基礎,基本上所有的組件都是依賴Unsafe來做底層的同步操作。

?

Unsafe類有100+個方法,大部分是native方法,可以理解為Java平臺和底層操作系統直接的橋梁。它封裝了大量的底層操作,比如直接操作內存的方法,低級同步的方法,CAS方法,直接操作Class的方法,直接操作Object的方法等等。有了Unsafe類,就可以像C, C++一樣精確地操作內存。當然Java的一大優點就是可以安全的操作內存,所以不提倡開發者直接使用Unsafe類。JDK本身的類很多都利用了Unsafe來進行底層操作。

?

Unsafe和并發編程相關的有幾類方法:

1. CAS方法

2. 操作條件隊列的方法,比如park()讓線程進入等待,unpark()喚醒線程

3. 存取volatile變量的方法,比如getBooleanVolatile, putBooleanVolatile

?

首先看看CAS方法,主要是3個comAndSwapXXX方法

1. compareAndSwapObject提供了對一個對象引用進行CAS的能力

2. compareAndSwapInt提供了對一個32位整數進行CAS操作的能力

3. compareAndSwapLong提供了對64位整數進行CAS操作的能力

關于CAS的概念請看這篇?聊聊高并發(十二)分析java.util.concurrent.atomic.AtomicStampedReference源碼來看如何解決CAS的ABA問題

?

?
  • public final class Unsafe{

  • ?
  • public final native boolean compareAndSwapObject(Object o, long offset,

  • Object expected,

  • Object x);

  • ?
  • /**

  • * Atomically update Java variable to <tt>x</tt> if it is currently

  • * holding <tt>expected</tt>.

  • * @return <tt>true</tt> if successful

  • */

  • public final native boolean compareAndSwapInt(Object o, long offset,

  • int expected,

  • int x);

  • ?
  • /**

  • * Atomically update Java variable to <tt>x</tt> if it is currently

  • * holding <tt>expected</tt>.

  • * @return <tt>true</tt> if successful

  • */

  • public final native boolean compareAndSwapLong(Object o, long offset,

  • long expected,

  • long x);

  • ?
  • ..............

  • }


  • 操作條件隊列的方法有兩個:

    ?

    1. park(boolean isAbsolute, long time), 這個方法會讓當前線程進入等待,并釋放鎖。Java并發包里的Condition接口的底層實現就是利用了Unsafe的park方法來實現的。第一個參數isAbsolute是表示用絕對時間還是相對事件,如果是絕對時間,就等待直到time,比如Condition接口的awaitUntil(Date deadline)。isAbsolute為false時,等待一個時間間隔

    2. unpark(Object thread)喚醒等待的線程,Condition的signal方法就是基于unpark實現的

    ?

    ?
  • /**

  • * Unblock the given thread blocked on <tt>park</tt>, or, if it is

  • * not blocked, cause the subsequent call to <tt>park</tt> not to

  • * block. Note: this operation is "unsafe" solely because the

  • * caller must somehow ensure that the thread has not been

  • * destroyed. Nothing special is usually required to ensure this

  • * when called from Java (in which there will ordinarily be a live

  • * reference to the thread) but this is not nearly-automatically

  • * so when calling from native code.

  • * @param thread the thread to unpark.

  • *

  • */

  • public native void unpark(Object thread);

  • ?
  • /**

  • * Block current thread, returning when a balancing

  • * <tt>unpark</tt> occurs, or a balancing <tt>unpark</tt> has

  • * already occurred, or the thread is interrupted, or, if not

  • * absolute and time is not zero, the given time nanoseconds have

  • * elapsed, or if absolute, the given deadline in milliseconds

  • * since Epoch has passed, or spuriously (i.e., returning for no

  • * "reason"). Note: This operation is in the Unsafe class only

  • * because <tt>unpark</tt> is, so it would be strange to place it

  • * elsewhere.

  • */

  • public native void park(boolean isAbsolute, long time);


  • 存取volatile變量的方法,這些方法讓Unsafe對象有了直接存取volatile變量的能力。

    ?

    ?

    ?
  • public native Object getObjectVolatile(Object obj, long l);

  • ?
  • public native void putObjectVolatile(Object obj, long l, Object obj1);

  • ?
  • public native int getIntVolatile(Object obj, long l);

  • ?
  • public native void putIntVolatile(Object obj, long l, int i);

  • ?
  • public native boolean getBooleanVolatile(Object obj, long l);

  • ?
  • public native void putBooleanVolatile(Object obj, long l, boolean flag);

  • ?
  • public native byte getByteVolatile(Object obj, long l);

  • ?
  • public native void putByteVolatile(Object obj, long l, byte byte0);

  • ?
  • public native short getShortVolatile(Object obj, long l);

  • ?
  • public native void putShortVolatile(Object obj, long l, short word0);

  • ?
  • public native char getCharVolatile(Object obj, long l);

  • ?
  • public native void putCharVolatile(Object obj, long l, char c);

  • ?
  • public native long getLongVolatile(Object obj, long l);

  • ?
  • public native void putLongVolatile(Object obj, long l, long l1);

  • ?
  • ? public native float getFloatVolatile(Object obj, long l);

  • ?
  • ??? public native void putFloatVolatile(Object obj, long l, float f);

  • ?
  • ??? public native double getDoubleVolatile(Object obj, long l);

  • ?
  • ??? public native void putDoubleVolatile(Object obj, long l, double d);

  • ?

  • 關于Unsafe對象的其他信息,比如如何得到Unsafe對象,比如如何直接操作內存,類似反射機制存取對象屬性,請查看這篇Java Magic 4. Part 4: sun.misc,Unsafe

    ?

    ?

    java.util.concurrent包提供了一個LockSupport類來封裝了Unsafe對象,來提供操作條件隊列的方法。

    ?

    來看一下LockSupport的實現,有幾點比較有意思

    1. 利用Unsafe直接操作內存來存取對象的能力來設置blocker

    Unsafe.objectFieldOffset可以獲得某個字段在對象所在內存的offset,有了這個offset,就可以通過對象的引用來找到字段所在的實際內存地址。這種做法在C++中常見,但是在Java中不推薦上層程序使用。

    這段代碼的意思是把arg對象設置到Thread的parkBlocker屬性上。

    Thread的parkBlocker屬性用來指出當前線程是在哪個對象上阻塞

    ?

    ?
  • public class LockSupport {

  • private LockSupport() {} // Cannot be instantiated.

  • ?
  • // Hotspot implementation via intrinsics API

  • private static final Unsafe unsafe = Unsafe.getUnsafe();

  • private static final long parkBlockerOffset;

  • ?
  • static {

  • try {

  • parkBlockerOffset = unsafe.objectFieldOffset

  • (java.lang.Thread.class.getDeclaredField("parkBlocker"));

  • } catch (Exception ex) { throw new Error(ex); }

  • }

  • ?
  • private static void setBlocker(Thread t, Object arg) {

  • // Even though volatile, hotspot doesn't need a write barrier here.

  • unsafe.putObject(t, parkBlockerOffset, arg);

  • }

  • ?
  • ?
  • public class Thread{

  • ?/**

  • ???? * The argument supplied to the current call to

  • ???? * java.util.concurrent.locks.LockSupport.park.

  • ???? * Set by (private) java.util.concurrent.locks.LockSupport.setBlocker

  • ???? * Accessed using java.util.concurrent.locks.LockSupport.getBlocker

  • ???? */

  • ??? volatile Object parkBlocker;

  • }


  • 2. park方法需要指明鎖對象,可以看到,park方法先setBlocker標記當前線程是在哪個鎖對象上等待,然后調用Unsafe的park方法,當Unsafe的park方法返回時表示已經退出等待,就把blocker設置為null.

    ?

    用jstack命令查看過線程狀態的同學肯定知道jstack能打印出線程是在哪個對象上block,這個對象就是這里的blocker

    ?

    ?
  • public static void park(Object blocker) {

  • Thread t = Thread.currentThread();

  • setBlocker(t, blocker);

  • unsafe.park(false, 0L);

  • setBlocker(t, null);

  • }

  • ?

    ?

    LockSupport的park()和unpark()方法和Object.wait(), notify方法都可以操作線程的等待和喚醒,但是兩者主要有兩個區別

    1. 面向的主體不同,LockSupport的park, unpark面向的是線程,而Object.wait, nofify面向的是對象

    2. 底層實現機制不同,可以看到Object的wait, notify方法也是native方法,Unsafe的park和unpark方法也是native方法,底層實現不同,Object.notify不能喚醒Unsafe park的線程。

    ?

    ?

    ?
  • public class Object{

  • public final native void wait(long timeout) throws InterruptedException;

  • ?
  • public final native void notify();

  • ?
  • public final native void notifyAll();

  • }

  • ?

    總結

    以上是生活随笔為你收集整理的聊聊高并发(十七)解析java.util.concurrent各个组件(一) 了解sun.misc.Unsafe类的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。