国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

從Thread.join說開去

incredible / 2718人閱讀

摘要:在進入狀態前,線程會將持有的鎖先釋放掉。被喚醒后的線程,拿不到鎖的線程將進入狀態,直到它們拿到鎖為止。在等待之后測試條件,如果條件不成立的話繼續等待,這對于確保安全性是必要的。

WAITING(TIMED_WAITING) 與 BLOCKED

看《Java特種兵》的時候發現,Thread.join可以使線程進入WAITING狀態,再結合姊妹篇線程的狀態我們可以了解到,有兩個類狀態非常接近:WAITING(TIMED_WAITING) 與 BLOCKED,這兩者都會讓線程看上去“阻塞”在某處了。

什么時候線程會進入WAITING(無限期等待)的狀態中呢?常用的有兩個,分別是①Object.wait without timeout,②Thread.join without timeout【另外還有③LockSupport的park方法,④Conditon的await方法】;TIMED_WAITING除了①Object.wait with timeout、②Thread.join with timeout,還需要添加一條③Thread.sleep方法【另外還有④LockSupport的parkNanos方法,帶有時間】。

在進入WAITING狀態前,線程會將持有的鎖先釋放掉。WAITING狀態中的線程需要被其他線程對同一個對象調用notify()或notifyAll()方法才能喚醒。被notifyAll()喚醒后的線程,拿不到鎖的線程將進入BLOCKED狀態,直到它們拿到鎖為止。簡而言之,WAITING類狀態中的線程和BLOCKED狀態中的線程的區別在于:WAITING狀態的線程需要被其他線程喚醒;BLOCKED中的線程,需要等待其他線程釋放鎖,此處的鎖特指synchronized塊。

見下圖

Join為什么會使線程進入WAITING(TIMED_WAITING) 狀態中呢?我們看一下底層代碼

    public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;
?
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
?
        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

從12、20行中可以看出,join方法底層調用的就是wait方法。

sleep與wait

同樣會使線程進入TIMED_WAITING狀態中的sleep和wait方法,它們之間有什么區別呢?

wait()

wait()方法釋放鎖

wait()是Object類的方法

wait()是非靜態方法

public final void wait() throws InterruptedException { //...}

wait()應該被notify()或者notifyAll()方法喚醒

wait()方法需要在循環中調用(推薦不強制)

waint()方法必須放在synchronized上下文(synchronized方法或代碼塊)中,不然會拋出IllegalMonitorStateException

sleep()

sleep()方法不會釋放鎖

sleep()是java.lang.Thread類的方法

sleep()是靜態方法

public static void sleep(long millis, int nanos) throws InterruptedException { //... }

sleep()方法是在特定時間后結束

sleep()方法最好不在放在循環中

sleep()方法可以在任意地方執行

wait為什么要放在循環中?
synchronized(obj) {
    while (!condition) { 
      obj.wait(); 
    }
}
這里引用一段《Effective Java》
始終應該使用wait循環模式來調用wait方法;永遠不要在循環之外調用wait方法。循環會在等待之前和之后測試條件。
在等待之前測試條件,當條件已經成立時就跳過等待,這對于確?;钚裕╨iveness)是必要的。如果條件已經成立,并且在線程等待之前,notify (或者notifyAll)方法已經被調用, 則無法保證該線程將會從等待中蘇醒過來。
在等待之后測試條件,如果條件不成立的話繼續等待,這對于確保安全性(safety)是必要的。當條件不成立的時候,如果線程繼續執行,則可能會破壞被鎖保護的約束關系。當條件不成立時,有下面一些理由可使一個線程蘇醒過來:
- 另一個線程可能已經得到了鎖,并且從一個線程調用notify那一刻起,到等待線程蘇醒過來的這段時間中,得到鎖的線程已經改變了受保護的狀態。 
- 條件并不成立,但是另一個線程可能意外地或惡意地調用了 notify。在公有可訪問的對象上等待,這些類實際上把自己暴露在了這種危險的境地中。公有可訪問對象的同步方法中包含的wait都會出現這樣知問題。
- 通知線程(notifying thread)在喚醒等待線程時可能會過度“大方”。例如,即使只有某一些等待線程的條件已經被滿足,但是通知線程可能仍然調用notifyAll。 
- 在沒有通知的情況下,等待線程也可能(但很少)會蘇醒過來。這被稱為“偽喚醒 (spurious wakeup)”

我們針對【跳過等待】和【繼續等待】舉個形象的例子:

針對【前置判斷,跳過等待】:如果是兩個狙擊手,在同時等待一個人(鎖),判斷條件是這個人還活著。如果沒有前置的判斷,在等待前不校驗這個人是否活著,那么當狙擊手甲殺死目標并通知狙擊手乙之后,乙才進入等待狀態,那么乙將會死等一個已經被殺死的目標,乙將失去活性(liveness)。

針對【后置判斷,繼續等待】:還是兩個狙擊手,如果他們被喚醒后,沒有后置校驗,那么將導致可笑的錯誤,比如狙擊手甲已經將目標殺死了,狙擊手乙被喚醒后,沒有再校驗條件,直接開槍殺人,將會殺死目標兩次。如果是冪等的還則罷了,不冪等的將導致錯誤。

綜上所述,wait前后都要校驗,而最好的辦法就是循環。

Thread.join后誰在WAITING?

從上文中我們已經知道了,join可以使線程處于WAITING狀態,那問題來了,是子線程處于WAITING狀態還是父線程處于WAITING狀態?我們做個小試驗:

public class TestJoin {
    public static void main(String[] args) throws InterruptedException {
        Thread.currentThread().setName("TestJoin main....");
        Thread joinThread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (; ; ) {
?
                }
            }
        }, "join thread");
?
        joinThread.start();
        joinThread.join();
    }
}

按照在線程的狀態中提供的方法,我們可以得到:

子線程即join的線程依舊是RUNNABLE狀態

"join thread" #10 prio=5 os_prio=31 tid=0x00007fca1b801000 nid=0x5503 runnable [0x0000700001725000]

java.lang.Thread.State: RUNNABLE

    at com.meituan.java8.thread.TestJoin$1.run(TestJoin.java:13)

    at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:

    - None

父線程(在此例中是主線程)為WAITING狀態

"TestJoin main...." #1 prio=5 os_prio=31 tid=0x00007fca1c003000 nid=0x1903 in Object.wait() [0x00007000003ec000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076ad94fa0> (a java.lang.Thread)
        at java.lang.Thread.join(Thread.java:1252)
        - locked <0x000000076ad94fa0> (a java.lang.Thread)
        at java.lang.Thread.join(Thread.java:1326)
        at com.meituan.java8.thread.TestJoin.main(TestJoin.java:20)
   Locked ownable synchronizers:
        - None

我們對代碼做稍稍改動,可以驗證sleep后的線程在什么狀態

        Thread joinThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    TimeUnit.MINUTES.sleep(30);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "sleeping thread");
"sleeping thread" #10 prio=5 os_prio=31 tid=0x00007f92620bc000 nid=0x5503 waiting on condition [0x00007000077b7000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at java.lang.Thread.sleep(Thread.java:340)
        at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
        at com.meituan.java8.thread.TestJoin$1.run(TestJoin.java:16)
        at java.lang.Thread.run(Thread.java:748)
   Locked ownable synchronizers:
        - None
參考文檔

https://javaconceptoftheday.c...

A thread enters into WAITING state when it calls wait() or join() method on an object. Before entering into WAITING state, thread releases the lock of the object it holds. It will remain in WAITING state until any other thread calls either notify() or notifyAll() on the same object.
Once the other thread calls notify() or notifyAll() on the same object, one or all the threads which are WAITING for lock of that object will be notified. All the notified threads will not get the object lock immediately. They will get the object lock on a priority basis once the current thread releases the lock. Until that they will be in BLOCKED state.
In simple terms, a thread will be in WAITING state if it is waiting for notification from other threads. A thread will be in BLOCKED state if it is waiting for other thread to release the lock it wants.

https://stackoverflow.com/que...

The difference is relatively simple.
In the BLOCKED state, a thread is about to enter a synchronized block, but there is another thread currently running inside a synchronized block on the same object. The first thread must then wait for the second thread to exit its block.
In the WAITING state, a thread is waiting for a signal from another thread. This happens typically by calling Object.wait(), or Thread.join(). The thread will then remain in this state until another thread calls Object.notify(), or dies.

https://stackoverflow.com/a/3...

wait()
wait() method releases the lock.
wait() is the method of Object class.
wait() is the non-static method - public final void wait() throws InterruptedException { //...}
wait() should be notified by notify() or notifyAll() methods.
wait() method needs to be called from a loop in order to deal with false alarm.
wait() method must be called from synchronized context (i.e. synchronized method or block), otherwise it will throw IllegalMonitorStateException
sleep()
sleep() method doesn"t release the lock.
sleep() is the method of java.lang.Thread class.
sleep() is the static method - public static void sleep(long millis, int nanos) throws InterruptedException { //... }
after the specified amount of time, sleep() is completed.
sleep() better not to call from loop(i.e. see code below).
sleep() may be called from anywhere. there is no specific requirement.

4.《Effective Java》第10章

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/73928.html

相關文章

  • 兩段簡單的程序開去

    摘要:有這么兩段小程序。毫無疑問,把這兩段小程序貼到瀏覽器里跑一下,能很快地得到答案。而在第二段小程序中,由于在中,表達式的值在運行之前將會被轉化,將會把表達式和聲明提升到當前作用域的頂部。兩段小程序,考考作用域和變量聲明提升,怎么樣,答對了么 有這么兩段小程序。 var goo = hello; function foo(){ if(true){ goo = world; ...

    young.li 評論0 收藏0
  • python綜合學習一之多線程

    摘要:如下面的例子,在學習線程時,將文件名命名為腳本完全正常沒問題,結果報下面的錯誤。最大的問題就是的多線程程序并不能利用多核的優勢比如一個使用了多個線程的計算密集型程序只會在一個單上面運行。 本文記錄學習Python遇到的問題和一些常用用法,注本開發環境的Python版本為2.7。 一、python文件命名 在python文件命名時,一定要注意不能和系統默認的模塊名沖突,否則會報錯。如下面...

    cjie 評論0 收藏0
  • Thread類源碼解讀(2)——線程狀態及常用方法

    摘要:如果線程還存活,線程就無限期等待,并讓出監視器鎖,進入狀態。當線程從狀態被喚醒后通過,或者是假喚醒將繼續競爭監視器鎖,當成功獲得監視器鎖后,他將從調用的地方恢復,繼續運行。 前言 系列文章目錄 上一篇我們討論了線程的創建,本篇我們來聊一聊線程的狀態轉換以及常用的幾個比較重要的方法。 本篇依然是通過源碼分析來了解這些知識。 本文源碼基于jdk1.8 。 閱讀完本文,你應當有能力回答以...

    luqiuwen 評論0 收藏0
  • python并發4:使用thread處理并發

    摘要:如果某線程并未使用很多操作,它會在自己的時間片內一直占用處理器和。在中使用線程在和等大多數類系統上運行時,支持多線程編程。守護線程另一個避免使用模塊的原因是,它不支持守護線程。 這一篇是Python并發的第四篇,主要介紹進程和線程的定義,Python線程和全局解釋器鎖以及Python如何使用thread模塊處理并發 引言&動機 考慮一下這個場景,我們有10000條數據需要處理,處理每條...

    joywek 評論0 收藏0

發表評論

0條評論

incredible

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<