91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Object提供的阻塞和喚醒API有什么用

發布時間:2021-12-30 10:57:07 來源:億速云 閱讀:110 作者:小新 欄目:大數據

這篇文章將為大家詳細講解有關Object提供的阻塞和喚醒API有什么用,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。


  

Object提供的阻塞和喚醒API

java.lang.Object作為所有非基本類型的基類,也就是說所有java.lang.Object的子類都具備阻塞和喚醒的功能。下面詳細分析Object提供的阻塞和喚醒API,它們有一共共同特點:必須在synchronized所修飾的代碼塊或者方法中使用。

 

阻塞等待-wait

等待-wait()方法提供了阻塞的功能,分超時和永久阻塞的版本,實際上,底層只提供了一個JNI方法:

// 這個是底層提供的JNI方法,帶超時的阻塞等待,響應中斷,其他兩個只是變體
public final native void wait(long timeoutMillis) throws InterruptedException;

// 變體方法1,永久阻塞,響應中斷
public final void wait() throws InterruptedException {
    wait(0L);
}

// 變體方法2,帶超時的阻塞,超時時間分兩段:毫秒和納秒,實際上納秒大于0直接毫秒加1(這么暴力...),響應中斷
public final void wait(long timeoutMillis, int nanos) throws InterruptedException {
    if (timeoutMillis < 0) {
        throw new IllegalArgumentException("timeoutMillis value is negative");
    }
    if (nanos < 0 || nanos > 999999) {
        throw new IllegalArgumentException("nanosecond timeout value out of range");
    }
    if (nanos > 0) {
        timeoutMillis++;
    }
    wait(timeoutMillis);
}
 

也就是只有一個wait(long timeoutMillis)方法是JNI接口,其他兩個方法相當于:

  • wait()等價于     wait(0L)
  • wait(long timeoutMillis, int nanos)在參數合法的情況下等價于     wait(timeoutMillis + 1L)

由于wait(long timeoutMillis, int nanos)是參數最完整的方法,它的API注釋特別長,這里直接翻譯和摘取它注釋中的核心要素:

  1. 當前線程阻塞等待直到被喚醒,喚醒的情況一般有三種:     notify(All)被調用、線程被中斷或者在指定了超時阻塞的情況下超過了指定的阻塞時間。
  2. 當前線程必須獲取此對象的監視器鎖(     「monitor lock」),也就是     「調用阻塞等待方法之前一個線程必須成為此對象的監視器鎖的擁有者」
  3. 用了     wait()方法之后,當前線程會把自身放到當前對象的等待集合(     wait-set),然后釋放所有在此對象上的同步聲明(then to relinquish any nd all synchronization claims on this object),謹記只有當前對象上的同步聲明會被釋放,當前線程在其他對象上的同步鎖只有在調用其     wait()方法之后才會釋放。
  4. 「Warning」:線程被喚醒之后(     notify()或者中斷)就會從等待集合(     wait-set)中移除并且重新允許被線程調度器調度。通常情況下,這個被喚醒的線程會與其他線程競爭對象上的同步權(鎖),一旦線程重新     「控制了對象(regained control of the object)」,它對對象的所有同步聲明都恢復到以前的狀態,即恢復到調用     wait()方法時(筆者認為,其實準確來說,是調用     wait()方法前)的狀態。
  5. 如果任意線程在它調用了     wait()之前,或者調用過     wait()方法之后處于阻塞等待狀態,一旦線程調用了     Thread#interrupt(),線程就會中斷并且拋出     InterruptedException異常,線程的中斷狀態會被清除。     InterruptedException異常會延遲到在第4點提到"它對對象的所有同步聲明都恢復到以前的狀態"的時候拋出。

值得注意的還有:

「一個線程必須成為此對象的監視器鎖的擁有者才能正常調用wait()系列方法,也就是wait()系列方法必須在同步代碼塊(synchronized代碼塊)中調用,否則會拋出IllegalMonitorStateException異常」,這一點是初學者或者不了解wait()的機制的開發者經常會犯的問題。

上面的五點描述可以寫個簡單的同步代碼塊偽代碼時序總結一下:


final Object lock = new Object();

synchronized(lock){
    1、線程進入同步代碼塊,意味著獲取對象監視器鎖成功
    while(!condition){
        lock.wait();   2.線程調用wait()進行阻塞等待
        break;
    }
    3.線程從wait()的阻塞等待中被喚醒,恢復到第1步之后的同步狀態
    4.繼續執行后面的代碼,直到離開同步代碼塊
}
   

喚醒-notify

notify()方法的方法簽名如下:

@HotSpotIntrinsicCandidate
public final native void notify();
 

下面按照慣例翻譯一下其API注釋:

  1. 喚醒一個阻塞等待在此對象監視器上的線程,(如果存在多個阻塞線程)至于選擇哪一個線程進行喚醒是任意的,取決于具體的現實,一個線程通過調用     wait()方法才能阻塞在對象監視器上。
  2. 被喚醒的線程并不會馬上繼續執行,直到當前線程(也就是當前調用了     notify()方法的線程)釋放對象上的鎖。被喚醒的線程會與其他線程競爭在對象上進行同步(換言之只有獲得對象的同步控制權才能繼續執行),在成為下一個鎖定此對象的線程時,被喚醒的線程沒有可靠的特權或劣勢。
  3. 此方法只有在一個線程獲取了此對象監視器的所有權(     the owner)的時候才能調用,具體就是:同步方法中、同步代碼塊中或者靜態同步方法中。否則,會拋出     IllegalMonitorStateException異常。
 

喚醒所有-notifyAll

notifyAll()方法的方法簽名如下:

@HotSpotIntrinsicCandidate
public final native void notifyAll();
 
  1. 喚醒所有阻塞等待在此對象監視器上的線程,一個線程通過調用     wait()方法才能阻塞在對象監視器上。

其他注釋的描述和notify()方法類似。

 

synchronized小結

我們經常看到的資料中提到synchronized關鍵字的用法:

  • 普通同步方法,同步或者說鎖定的是當前實例對象。
  • 靜態同步方法,同步或者說鎖定的是當前實例對象的     Class對象。
  • 同步代碼塊,同步或者說鎖定的是括號里面的實例對象。

對于同步代碼塊而言,synchronized關鍵字抽象到字節碼層面就是同步代碼塊中的字節碼執行在monitorentermonitorexit指令之間:

synchronized(xxxx){

    ...coding block
}

↓↓↓↓↓↓↓↓↓↓

monitorenter;
...coding block - bytecode
monitorexit;
 

JVM需要保證每一個monitorenter都有一個monitorexit與之相對應。任何對象都有一個monitor(實際上是ObjectMonitor)與之相關聯,當且僅當一個monitor被持有之后,它將處于鎖定狀態。線程執行到monitorenter指令時,將會嘗試獲取對象所對應的monitor所有權,即嘗試獲取對象的鎖。

對于同步(靜態)方法而言,synchronized方法則會被翻譯成普通的方法調用和返回指令,如:invokevirtual等等,在JVM字節碼層面并沒有任何特別的指令來實現被synchronized修飾的方法,而是在Class文件的方法表中將該方法的access_flags字段中的synchronized標志位置1,表示該方法是同步方法并使用調用該方法的對象或該方法所屬的ClassJVM的內部對象表示Klass作為鎖對象。

其實從開發者角度簡單理解,「這兩種方式只是在獲取鎖的時機有所不同」

下面重復闡述「幾個第一眼看起來不合理卻是事實的問題」(其實前文已經提及過):

  1. 在線程進入     synchronized方法或者代碼塊,相當于獲取監視器鎖成功,如果此時成功調用     wait()系列方法,那么它會立即釋放監視器鎖,并且添加到等待集合(     Wait Set)中進行阻塞等待。
  2. 由于已經有線程釋放了監視器鎖,那么在另一個線程進入     synchronized方法或者代碼塊之后,它可以調用     notify(All)方法喚醒等待集合中正在阻塞的線程,但是這個喚醒操作并不是調用     notify(All)方法后立即生效,而是在該線程     「退出synchronized方法或者代碼塊之后才生效」
  3. 從     wait()方法阻塞過程中被喚醒的線程會競爭監視器目標對象的控制權,一旦重新控制了對象,那么線程的同步狀態就會恢復到步入     synchronized方法或者代碼塊時候的狀態(也就是成功獲取到對象監視器鎖時候的狀態),這個時候線程才能夠繼續執行。

為了驗證這三點,可以寫個簡單的Demo

public class Lock {

}

public class WaitMain {

    private static final DateTimeFormatter F = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    public static void main(String[] args) throws Exception {
        // 這里換成Object其實也沒有問題
        final Lock lock = new Lock();
        new Thread(new  WaitRunnable(lock), "WaitThread-1").start();
        new Thread(new  WaitRunnable(lock), "WaitThread-2").start();
        Thread.sleep(50);
        new Thread(new  NotifyRunnable(lock), "NotifyThread").start();
        Thread.sleep(Integer.MAX_VALUE);
    }

    @RequiredArgsConstructor
    private static class WaitRunnable implements Runnable {

        private final Lock lock;

        @Override
        public void run() {
            synchronized (lock) {
                System.out.println(String.format("[%s]-線程[%s]獲取鎖成功,準備執行wait方法", F.format(LocalDateTime.now()),
                        Thread.currentThread().getName()));
                while (true) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        //ignore
                    }
                    System.out.println(String.format("[%s]-線程[%s]從wait中喚醒,準備exit", F.format(LocalDateTime.now()),
                            Thread.currentThread().getName()));
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        //ignore
                    }
                    break;
                }
            }
        }
    }

    @RequiredArgsConstructor
    private static class NotifyRunnable implements Runnable {

        private final Lock lock;

        @Override
        public void run() {
            synchronized (lock) {
                System.out.println(String.format("[%s]-線程[%s]獲取鎖成功,準備執行notifyAll方法", F.format(LocalDateTime.now()),
                        Thread.currentThread().getName()));
                lock.notifyAll();
                System.out.println(String.format("[%s]-線程[%s]先休眠3000ms", F.format(LocalDateTime.now()),
                        Thread.currentThread().getName()));
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    //ignore
                }
                System.out.println(String.format("[%s]-線程[%s]準備exit", F.format(LocalDateTime.now()),
                        Thread.currentThread().getName()));
            }
        }
    }
}
 

某個時刻的執行結果如下:

[2019-04-27 23:28:17.617]-線程[WaitThread-1]獲取鎖成功,準備執行wait方法
[2019-04-27 23:28:17.631]-線程[WaitThread-2]獲取鎖成功,準備執行wait方法
[2019-04-27 23:28:17.657]-線程[NotifyThread]獲取鎖成功,準備執行notifyAll方法 <-------- 這一步執行完說明WaitThread已經釋放了鎖
[2019-04-27 23:28:17.657]-線程[NotifyThread]先休眠3000ms
[2019-04-27 23:28:20.658]-線程[NotifyThread]準備exit <------- 這一步后NotifyThread離開同步代碼塊
[2019-04-27 23:28:20.658]-線程[WaitThread-1]從wait中喚醒,準備exit <------- 這一步WaitThread-1解除阻塞
[2019-04-27 23:28:21.160]-線程[WaitThread-2]從wait中喚醒,準備exit <------- 這一步WaitThread-2解除阻塞,注意發生時間在WaitThread-1解除阻塞500ms之后,符合我們前面提到的第3點
 

如果結合wait()notify()可以簡單總結出一個同步代碼塊的偽代碼如下:

final Object lock = new Object();

// 等待
synchronized(lock){
    1、線程進入同步代碼塊,意味著獲取對象監視器鎖成功
    while(!condition){
        lock.wait();   2.線程調用wait()進行阻塞等待
        break;
    }
    3.線程從wait()的阻塞等待中被喚醒,嘗試恢復第1步之后的同步狀態,并不會馬上生效,直到notify被調用并且調用notify方法的線程已經釋放鎖,同時當前線程需要競爭成功
    4.繼續執行后面的代碼,直到離開同步代碼塊
}

// 喚醒
synchronized(lock){
    1、線程進入同步代碼塊,意味著獲取對象監視器鎖成功
    lock.notify();  2.喚醒其中一個在對象監視器上等待的線程
    3.準備推出同步代碼塊釋放鎖,只有釋放鎖之后第2步才會生效
}
   

圖解Object提供的阻塞和喚醒機制

結合前面分析過的知識點以及參考資料中的文章,重新畫一個圖理解一下對象監視器以及相應阻塞和喚醒API的工作示意過程:

Object提供的阻塞和喚醒API有什么用  
j-u-c-o-w-n-1.png
  • Entry Set(實際上是     ObjectMonitor中的     _EntryList屬性):存放等待鎖并且處于阻塞狀態的線程。
  • Wait Set(實際上是     ObjectMonitor中的     _WaitSet屬性):存放處于等待阻塞狀態的線程。
  • The Owner(實際上是     ObjectMonitor中的     _owner屬性):指向獲得對象監視器的線程,在同一個時刻只能有一個線程被     The Owner持有,通俗來看,它就是監視器的控制權。
 

使用例子

通過Object提供的阻塞和喚醒機制舉幾個簡單的使用例子。

 

維修廁所的例子

假設有以下場景:廁所的只有一個卡位,廁所維修工修廁所的時候,任何人不能上廁所。當廁所維修工修完廁所的時候,上廁所的人需要"得到廁所的控制權"才能上廁所。

// 廁所類
public class Toilet {
    // 廁所的鎖
    private final Object lock = new Object();
    private boolean available;

    public Object getLock() {
        return lock;
    }

    public void setAvailable(boolean available) {
        this.available = available;
    }

    public boolean getAvailable() {
        return available;
    }
}

// 廁所維修工
@RequiredArgsConstructor
public class ToiletRepairer implements Runnable {

    private static final DateTimeFormatter F = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    private final Toilet toilet;

    @Override
    public void run() {
        synchronized (toilet.getLock()) {
            System.out.println(String.format("[%s]-廁所維修員得到了廁所的鎖,維修廁所要用5000ms...", LocalDateTime.now().format(F)));
            try {
                Thread.sleep(5000);
            } catch (Exception e) {
                // ignore
            }
            toilet.setAvailable(true);
            toilet.getLock().notifyAll();
            System.out.println(String.format("[%s]-廁所維修員維修完畢...", LocalDateTime.now().format(F)));
        }
    }
}

//上廁所的任務
@RequiredArgsConstructor
public class ToiletTask implements Runnable {

    private static final DateTimeFormatter F = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    private final Toilet toilet;
    private final String name;
    private final Random random;

    @Override
    public void run() {
        synchronized (toilet.getLock()) {
            System.out.println(String.format("[%s]-%s得到了廁所的鎖...", LocalDateTime.now().format(F), name));
            while (!toilet.getAvailable()) {
                try {
                    toilet.getLock().wait();
                } catch (InterruptedException e) {
                    //ignore
                }
                int time = random.nextInt(3) + 1;
                try {
                    // 模擬上廁所用時
                    TimeUnit.SECONDS.sleep(time);
                } catch (InterruptedException e) {
                    //ignore
                }
                System.out.println(String.format("[%s]-%s上廁所用了%s秒...", LocalDateTime.now().format(F), name, time));
            }
        }
    }
}

// 場景入口
public class Main {

    public static void main(String[] args) throws Exception {
        Toilet toilet = new Toilet();
        Random random = new Random();
        Thread toiletRepairer = new Thread(new ToiletRepairer(toilet), "ToiletRepairer");
        Thread thread1 = new Thread(new ToiletTask(toilet, "張三", random), "thread-1");
        Thread thread2 = new Thread(new ToiletTask(toilet, "李四", random), "thread-2");
        Thread thread3 = new Thread(new ToiletTask(toilet, "王五", random), "thread-3");
        thread1.start();
        thread2.start();
        thread3.start();
        Thread.sleep(50);
        toiletRepairer.start();
        Thread.sleep(Integer.MAX_VALUE);
    }
}
 

某次執行的結果如下:

[2019-04-29 01:07:25.914]-張三得到了廁所的鎖...
[2019-04-29 01:07:25.931]-李四得到了廁所的鎖...
[2019-04-29 01:07:25.931]-王五得到了廁所的鎖...
[2019-04-29 01:07:25.951]-廁所維修員得到了廁所的鎖,維修廁所要用5000ms...
[2019-04-29 01:07:30.951]-廁所維修員維修完畢...
[2019-04-29 01:07:32.952]-張三上廁所用了2秒...
[2019-04-29 01:07:35.952]-王五上廁所用了3秒...
[2019-04-29 01:07:37.953]-李四上廁所用了2秒...
   

阻塞隊列實現

實現一個簡單固定容量的阻塞隊列,接口如下:

public interface BlockingQueue<T> {

    void put(T value) throws InterruptedException;

    T take() throws InterruptedException;
}
 

其中put(T value)會阻塞直到隊列中有可用的容量,而take()方法會阻塞直到有元素投放到隊列中。實現如下:

public class DefaultBlockingQueue<T> implements BlockingQueue<T> {

    private Object[] elements;
    private final Object notEmpty = new Object();
    private final Object notFull = new Object();
    private int count;
    private int takeIndex;
    private int putIndex;

    public DefaultBlockingQueue(int capacity) {
        this.elements = new Object[capacity];
    }

    @Override
    public void put(T value) throws InterruptedException {
        synchronized (notFull) {
            while (count == elements.length) {
                notFull.wait();
            }
        }
        final Object[] items = this.elements;
        items[putIndex] = value;
        if (++putIndex == items.length) {
            putIndex = 0;
        }
        count++;
        synchronized (notEmpty) {
            notEmpty.notify();
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public T take() throws InterruptedException {
        synchronized (notEmpty) {
            while (count == 0) {
                notEmpty.wait();
            }
        }
        final Object[] items = this.elements;
        T value = (T) items[takeIndex];
        items[takeIndex] = null;
        if (++takeIndex == items.length) {
            takeIndex = 0;
        }
        count--;
        synchronized (notFull) {
            notFull.notify();
        }
        return value;
    }
}
 

場景入口類:

public class Main {

    public static void main(String[] args) throws Exception {
        BlockingQueue<String> queue = new DefaultBlockingQueue<>(5);
        Runnable r = () -> {
            while (true) {
                try {
                    String take = queue.take();
                    System.out.println(String.format("線程%s消費消息-%s", Thread.currentThread().getName(), take));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        new Thread(r, "thread-1").start();
        new Thread(r, "thread-2").start();

        IntStream.range(0, 10).forEach(i -> {
            try {
                queue.put(String.valueOf(i));
            } catch (InterruptedException e) {
                //ignore
            }
        });

        Thread.sleep(Integer.MAX_VALUE);
    }
}
 

某次執行結果如下:

線程thread-1消費消息-0
線程thread-2消費消息-1
線程thread-1消費消息-2
線程thread-2消費消息-3
線程thread-1消費消息-4
線程thread-2消費消息-5
線程thread-1消費消息-6
線程thread-2消費消息-7
線程thread-1消費消息-8
線程thread-2消費消息-9
 

上面這個例子就是簡單的單生產者-多消費者的模型。

 

線程池實現

這里實現一個極度簡陋的固定容量的線程池,功能是:初始化固定數量的活躍線程,阻塞直到有可用的線程用于提交任務。它只有一個接口方法,接口定義如下:

public interface ThreadPool {

    void execute(Runnable runnable);
}
 

具體實現如下:

public class DefaultThreadPool implements ThreadPool {

    private final int capacity;
    private List<Worker> initWorkers;
    private Deque<Worker> availableWorkers;
    private Deque<Worker> busyWorkers;
    private final Object nextLock = new Object();

    public DefaultThreadPool(int capacity) {
        this.capacity = capacity;
        init(capacity);
    }

    private void init(int capacity) {
        initWorkers = new ArrayList<>(capacity);
        availableWorkers = new LinkedList<>();
        busyWorkers = new LinkedList<>();
        for (int i = 0; i < capacity; i++) {
            Worker worker = new Worker();
            worker.setName("Worker-" + (i + 1));
            worker.setDaemon(true);
            initWorkers.add(worker);
        }
        for (Worker w : initWorkers) {
            w.start();
            availableWorkers.add(w);
        }
    }

    @Override
    public void execute(Runnable runnable) {
        if (null == runnable) {
            return;
        }
        synchronized (nextLock) {
            while (availableWorkers.size() < 1) {
                try {
                    nextLock.wait(500);
                } catch (InterruptedException e) {
                    //ignore
                }
            }
            Worker worker = availableWorkers.removeFirst();
            busyWorkers.add(worker);
            worker.run(runnable);
            nextLock.notifyAll();
        }
    }

    private void makeAvailable(Worker worker) {
        synchronized (nextLock) {
            availableWorkers.add(worker);
            busyWorkers.remove(worker);
            nextLock.notifyAll();
        }
    }

    private class Worker extends Thread {

        private final Object lock = new Object();
        private Runnable runnable;
        private AtomicBoolean run = new AtomicBoolean(true);

        private void run(Runnable runnable) {
            synchronized (lock) {
                if (null != this.runnable) {
                    throw new IllegalStateException("Already running a Runnable!");
                }
                this.runnable = runnable;
                lock.notifyAll();
            }
        }

        @Override
        public void run() {
            boolean ran = false;
            while (run.get()) {
                try {
                    synchronized (lock) {
                        while (runnable == null && run.get()) {
                            lock.wait(500);
                        }

                        if (runnable != null) {
                            ran = true;
                            runnable.run();
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    synchronized (lock) {
                        runnable = null;
                    }
                    if (ran) {
                        ran = false;
                        makeAvailable(this);
                    }
                }
            }
        }
    }
}
 

編寫一個場景類:

public class MainClient {

    private static final DateTimeFormatter F = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    public static void main(String[] args) throws Exception{
        ThreadPool threadPool = new DefaultThreadPool(2);
        threadPool.execute(() -> {
            try {
                System.out.println(String.format("[%s]-任務一開始執行持續3秒...", LocalDateTime.now().format(F)));
                Thread.sleep(3000);
                System.out.println(String.format("[%s]-任務一執行結束...", LocalDateTime.now().format(F)));
            }catch (Exception e){
                //ignore
            }
        });
        threadPool.execute(() -> {
            try {
                System.out.println(String.format("[%s]-任務二開始執行持續4秒...", LocalDateTime.now().format(F)));
                Thread.sleep(4000);
                System.out.println(String.format("[%s]-任務二執行結束...", LocalDateTime.now().format(F)));
            }catch (Exception e){
                //ignore
            }
        });
        threadPool.execute(() -> {
            try {
                System.out.println(String.format("[%s]-任務三開始執行持續5秒...", LocalDateTime.now().format(F)));
                Thread.sleep(5000);
                System.out.println(String.format("[%s]-任務三執行結束...", LocalDateTime.now().format(F)));
            }catch (Exception e){
                //ignore
            }
        });
        Thread.sleep(Integer.MAX_VALUE);
    }
}
 

某次執行結果如下:

[2019-04-29 02:07:25.465]-任務二開始執行持續4秒...
[2019-04-29 02:07:25.465]-任務一開始執行持續3秒...
[2019-04-29 02:07:28.486]-任務一執行結束...
[2019-04-29 02:07:28.486]-任務三開始執行持續5秒...
[2019-04-29 02:07:29.486]-任務二執行結束...
[2019-04-29 02:07:33.487]-任務三執行結束...
   

小結

鑒于筆者C語言學得不好,這里就無法深入分析JVM源碼的實現,只能結合一些現有的資料和自己的理解重新梳理一下Object提供的阻塞和喚醒機制這些知識點。結合之前看過JUC同步器的源碼,一時醒悟過來,JUC同步器只是在數據結構和算法層面使用Java語言對原來JVMC語言的阻塞和喚醒機制即Object提供的那幾個JNI方法進行了一次實現而已。

最后,Object提供的阻塞等待喚醒機制是JVM實現的(如果特別熟悉C語言可以通過JVM源碼研究其實現,對于大部分開發者來說這部分的知識其實是暗箱),除非是特別熟練或者是JDK版本太低尚未引入JUC包(JUC包是JDK1.5或者之后才加入到JDK中)。一般情況下「不應該優先選擇Object,一方面因為Object提供的APINative方法,其功能有可能受到JVM版本的影響(有可能帶來性能提升這樣的正面影響,也有可能是負面影響),另一方面Object提供的API其實并不靈活。綜合來看,實際開發中更建議使用專門為并發設計的JUC包中的鎖相關類庫,例如可重入鎖ReentrantLock

?  

話雖然這樣說,但是筆者發現了在JDK1.5之后的一些版本中,有部分原來使用了ReentrantLock的類庫被重新換回去Object提供的API以及synchronized,原因是:更喜歡使用synchronized和Object Monitor。具體是哪些類一時想不起來,是很久一段時間之前看源碼的注釋看到的。看來JDK的開發者也是有脾氣的.....

?  

直到JDK11為止,還有大量的JDK類庫使用了Object提供的API以及synchronized關鍵字實現的阻塞和喚醒功能,此所謂存在即合理。

關于“Object提供的阻塞和喚醒API有什么用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

青川县| 子洲县| 德令哈市| 个旧市| 成安县| 融水| 华蓥市| 苍梧县| 穆棱市| 蓝山县| 元朗区| 崇义县| 元谋县| 西盟| 东海县| 定安县| 长海县| 贵定县| 宣武区| 福鼎市| 东宁县| 家居| 揭西县| 京山县| 竹溪县| 镇坪县| 楚雄市| 中江县| 四川省| 玉山县| 安平县| 马关县| 扶沟县| 怀宁县| 麦盖提县| 毕节市| 清水河县| 都安| 鸡东县| 上林县| 皋兰县|