1. 程式人生 > 資訊 >胡厚崑否認華為將新增 “養豬”等業務傳聞

胡厚崑否認華為將新增 “養豬”等業務傳聞

javadoc

用於建立鎖和其他同步類的基本執行緒阻塞原語。

這個類與每個使用它的執行緒相關聯,一個許可證(在Semaphore類的意義上)。如果許可證可用,則呼叫parkpark返回,在此過程中消耗它;否則可能會阻止。

呼叫unpark使許可證可用,如果尚不可用。(與訊號量不同,許可證不能累積,最多隻有一個。)

方法parkunpark提供了阻止和解除阻塞執行緒的有效手段,該方法不會遇到導致不推薦使用的方法Thread.suspendThread.resume目的不能使用的問題:

一個執行緒呼叫park和另一個執行緒之間的嘗試unpark執行緒將保持活躍性,由於許可證。另外,如果呼叫者的執行緒被中斷,park

將返回,並且支援超時版本。park方法也可以在任何其他時間返回,因為“無理由”,因此一般必須在返回之前重新檢查條件的迴圈中被呼叫。在這個意義上,park作為一個“忙碌等待”的優化,不浪費時間旋轉,但必須與unpark配對才能有效。

park的三種形式也支援blocker物件引數。執行緒被阻止時記錄此物件(blocker--LockSupport的一個屬性),以允許監視和診斷工具識別執行緒被阻止的原因。(此類工具可以使用方法getBlocker(Thread)訪問阻止程式。)強烈鼓勵使用這些形式而不是沒有此引數的原始形式。在鎖實現中作為blocker提供的正常引數是this

這些方法被設計為用作建立更高階同步實用程式的工具,並且本身對於大多數併發控制應用程式本身並不有用。park

方法僅用於形式的構造:

樣板用例

class FIFOMutex {
   private final AtomicBoolean locked = new AtomicBoolean(false);
   private final Queue<Thread> waiters = new ConcurrentLinkedQueue<Thread>();

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

中斷的響應性

class LockSupportTest {

    public static void t2() throws Exception {
        Thread t = new Thread(new Runnable() {
            private int count = 0;
            @Override
            public void run() {
                long start = System.currentTimeMillis();
                long end = 0;
                while ((end - start) <= 1000) {
                    count++;
                    end = System.currentTimeMillis();
                }
                System.out.println("after 1 second.count=" + count);
                //等待或許許可
                LockSupport.park();
                System.out.println("thread over." + Thread.currentThread().isInterrupted());

            }
        });
        t.start();
        Thread.sleep(2000);
        // 中斷執行緒
        t.interrupt();
        System.out.println("main over");
    }

結果:

after 1 second.count=286194848
main over
thread over.true

結論:

中斷執行緒(t.interrupt())可以起到釋放uppark的作用.

不會丟擲:InterruptedException異常

原始碼

來看一下LockSupport原始碼,其中有兩個屬性unsafe 和 parkBlokcerOffset

 // Hotspot implementation via intrinsics API
    private static final sun.misc.Unsafe UNSAFE;
    private static final long parkBlockerOffset;
    private static final long SEED;
    private static final long PROBE;
    private static final long SECONDARY;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> tk = Thread.class;
            parkBlockerOffset = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("parkBlocker"));
            SEED = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSeed"));
            PROBE = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomProbe"));
            SECONDARY = UNSAFE.objectFieldOffset
                (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
        } catch (Exception ex) { throw new Error(ex); }
    }

unsafe:是JDK內部用的工具類。它通過暴露一些Java意義上說“不安全”的功能給Java層程式碼,來讓JDK能夠更多的使用Java程式碼來實現一些原本是平臺相關的、需要使用native語言(例如C或C++)才可以實現的功能。該類不應該在JDK核心類庫之外使用。

parkBlokcerOffset:parkBlocker的偏移量,讓我們來看看Thread類的實現:

parkBlocker是用於記錄執行緒是被誰阻塞的。可以通過LockSupport的getBlocker獲取到阻塞的物件。用於監控和分析執行緒用的。

偏移量就算Thread這個類裡面變數parkBlocker在記憶體中的偏移量,直接通過記憶體偏移量給變數賦值.

為什麼要用偏移量來獲取物件?幹嗎不要直接寫個get,set方法。多簡單?

仔細想想就能明白,這個parkBlocker就是線上程處於阻塞的情況下才會被賦值。執行緒都已經阻塞了,如果不通過這種記憶體的方法,而是直接呼叫執行緒內的方法,執行緒是不會迴應呼叫的。

Unsafe記憶體操作

public class UnsafeDemo {
 
    private int i = 0;
 
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        //獲取Unsafe例項
        Field f = Unsafe.class.getDeclaredField("theUnsafe"); // Internal reference
        f.setAccessible(true);
        Unsafe unsafe = (Unsafe) f.get(null);
 
        //獲取欄位i在記憶體中偏移量
        long offset = unsafe.objectFieldOffset(UnsafeDemo.class.getDeclaredField("i"));
 
        //建立物件例項,設定欄位的值
        UnsafeDemo unsafeDemo = new UnsafeDemo();
        unsafe.putInt(unsafeDemo, offset, 100);
 
        //列印結果
        System.out.println(unsafeDemo.i);
    }
}

說明

JVM的實現可以自由選擇如何實現Java物件的“佈局”,也就是在記憶體裡Java物件的各個部分放在哪裡,包括物件的例項欄位和一些元資料之類。

sun.misc.Unsafe裡關於物件欄位訪問的方法把物件佈局抽象出來,它提供了objectFieldOffset()方法用於獲取某個欄位相對Java物件的“起始地址”的偏移量,

也提供了getInt、getLong、getObject之類的方法可以使用前面獲取的偏移量來訪問某個Java物件的某個欄位。

在上例中,我們通過putInt方法給一個int變數i賦值,類似的,Unsafe也提供了putLong、putFloat、putDouble、putChar、putByte、putShort、putBoolean、以及putObject等方法給對應型別的變數賦值。

並提供了相應的get方法。

參考:

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/LockSupport.html

http://www.tianshouzhi.com/api/tutorials/mutithread/304