Java四個線程常用函數(shù)超全使用詳解
前言
之前沒怎么關(guān)注到這兩個的區(qū)別以及源碼探討
后面被某個公司面試問到了,開始查漏補缺
1. wait()
使當前線程等待,直到它被喚醒,通常是通過被通知或被中斷,或者直到經(jīng)過一定的實時時間。
本身屬于一個Object 類,查看源代碼也可知:public class Object {
查看其源碼可知,一共有三個重載的方法,詳情源代碼如下:
//第一個重載函數(shù)
public final void wait() throws InterruptedException {
wait(0L);
}
//第二個重載函數(shù)
public final native void wait(long timeoutMillis) throws InterruptedException;
//第三個重載函數(shù)
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 < Long.MAX_VALUE) {
timeoutMillis++;
}
wait(timeoutMillis);
}
具體實戰(zhàn)調(diào)用代碼如下:
如果執(zhí)行到了wait函數(shù),在這4秒內(nèi),會釋放鎖,并且暫停線程。如果這四秒內(nèi)配合notify()可以喚醒并且得到鎖,如果沒有喚醒,等待其他來競爭。4秒結(jié)束后,會默認自動釋放鎖
當前線程在 Thread.wait()等待過程中,如果Thread結(jié)束了,是可以自動喚醒的而且自動釋放鎖
@Override
public void run() {
synchronized (a) {
a.wait(4000);
}
}
2. join()
join是Thread類的方法
查看其源碼,具體源碼如下,三個重載的方法
//第一個重載函數(shù)
public final synchronized void join(final long millis)
throws InterruptedException {
if (millis > 0) {
if (isAlive()) {
final long startTime = System.nanoTime();
long delay = millis;
do {
wait(delay);
} while (isAlive() && (delay = millis -
TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0);
}
} else if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
throw new IllegalArgumentException("timeout value is negative");
}
}
//第二個重載函數(shù)
/*等待該線程死亡的時間最多為毫秒加納秒。 如果兩個參數(shù)都為0,則意味著永遠等待。
這個實現(xiàn)使用了This的循環(huán)。 等待電話以this.isAlive為條件。 當一個線程終止this。
調(diào)用notifyAll方法。 建議應用程序不要使用wait、notify或notifyAll on Thread實例。 */
public final synchronized void join(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0 && millis < Long.MAX_VALUE) {
millis++;
}
join(millis);
}
//第三個重載函數(shù)
/*等待線程死亡。
此方法的調(diào)用與調(diào)用的行為完全相同
InterruptedException—如果任何線程中斷了當前線程。 當拋出此異常時,當前線程的中斷狀態(tài)將被清除。 */
public final void join() throws InterruptedException {
join(0);
}
主要的時間參數(shù)邏輯如下:
- 小于0,拋出異常
- 等于0,join(A),判斷A是否存在,存在才執(zhí)行操作。該線程執(zhí)行wait(0)等待,等待A線程執(zhí)行完后才可結(jié)束
- 大于0,同上,只不過執(zhí)行的是wait(long millis),等待時間結(jié)束后才可繼續(xù)執(zhí)行操作
3. sleep()
對比上一個wait函數(shù)
- sleep(long mills):讓出CPU資源,但是不會釋放鎖資源。
- wait():讓出CPU資源和鎖資源。
查看sleep函數(shù)的源碼,一共有兩個重載函數(shù)
都是Thread類的函數(shù)
/*根據(jù)系統(tǒng)計時器和調(diào)度器的精度和準確性,
使當前執(zhí)行的線程在指定的毫秒數(shù)內(nèi)處于睡眠狀態(tài)(暫時停止執(zhí)行)。
線程不會失去任何監(jiān)視器的所有權(quán)。*/
public static native void sleep(long millis) throws InterruptedException;
/*導致當前執(zhí)行的線程在指定的毫秒數(shù)加上指定的納秒數(shù)
(取決于系統(tǒng)計時器和調(diào)度器的精度和準確性)內(nèi)休眠(暫時停止執(zhí)行)。
線程不會失去任何監(jiān)視器的所有權(quán)。 */
public static void sleep(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0 && millis < Long.MAX_VALUE) {
millis++;
}
sleep(millis);
}
4. yield()
查看yield()函數(shù)的源碼,一個重載函數(shù)
都是Thread類的函數(shù)
向調(diào)度器暗示當前線程愿意放棄當前對處理器的使用。 調(diào)度器可以忽略這個提示。
Yield是一種啟發(fā)式嘗試,旨在改善線程之間的相對進程,否則會過度使用CPU。 它的使用應該與詳細的分析和基準測試相結(jié)合,以確保它實際上具有預期的效果。
使用這種方法很少是合適的。 它可能用于調(diào)試或測試目的,在這些目的中,它可能有助于由于競爭條件而重新生成錯誤。 在設(shè)計并發(fā)控制構(gòu)造(如java.util.concurrent.locks包中的構(gòu)造)時,它可能也很有用。
public static native void yield();
總的來說,yield函數(shù)的功能主要是:
讓出CPU調(diào)度,暫停線程,但不能由用戶指定時間
只能讓同優(yōu)先級有執(zhí)行機會
5. 總結(jié)
wait 暫停該線程,讓出cpu,釋放鎖。(Object類)
join暫停該線程,執(zhí)行該線程之后才能回到自身的線程運行。(Thread類)
sleep 暫停該線程,讓出cpu,不釋放鎖。(Thread類)
yield 暫停該線程,但是不能由用戶制定,只能讓同優(yōu)先級有執(zhí)行機會。(Thread類)
5.1 wait和join的區(qū)別
看完以上的源碼以及邏輯代碼,再講講兩者的異同
總的來說
- wait函數(shù):讓當前線程進入等待狀態(tài),wait()會與notify()和notifyAll()方法一起使用。notify為喚醒函數(shù)
- join函數(shù):等待這個線程結(jié)束才能執(zhí)行自已的線程。它的主要起同步作用,使線程之間的執(zhí)行從“并行”變成“串行”。線程A中調(diào)用了線程B的join()方法時,線程
執(zhí)行過程發(fā)生改變:線程A,必須等待線程B執(zhí)行完畢后,才可以繼續(xù)執(zhí)行下去
共同點:
- 暫停當前的線程
- 都可以通過中斷喚醒
不同點在于:
| 區(qū)別 | wait | join |
|---|---|---|
| 類 | Object類 | Thread類 |
| 目的 | 線程間通信 | 排序,讓其串行通過 |
| 同步 | 必須要synchronized | 可以不用synchronized |
5.2 wait和sleep的區(qū)別
wait():讓出CPU資源和鎖資源。
sleep(long mills):讓出CPU資源,但是不會釋放鎖資源。
看區(qū)別,主要是看CPU的運行機制:
它們的區(qū)別主要考慮兩點:1.cpu是否繼續(xù)執(zhí)行、2.鎖是否釋放掉。
歸根到底:
wait,notify,notifyall 都是Object對象的方法,是一起使用的,用于鎖機制,所以會釋放鎖
而sleep是Thread類,跟鎖沒關(guān)系,不會釋放鎖
但是兩者都會讓出cpu資源
以上就是Java四個線程常用函數(shù)超全使用詳解的詳細內(nèi)容,更多關(guān)于Java線程函數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!

