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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java wait forever_彻底搞清楚Java并发 (一) 基础

發(fā)布時(shí)間:2025/3/20 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java wait forever_彻底搞清楚Java并发 (一) 基础 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

多線程編程是為了讓程序運(yùn)行得更快,但是不是說,線程創(chuàng)建地越多越好,線程切換的時(shí)候上下文切換,以及受限于硬件和軟件資源的限制問題

上下文切換

單核CPU同樣支持多線程編程,CPU通過給每個(gè)線程分配CPU時(shí)間片來實(shí)現(xiàn)這個(gè)機(jī)制,時(shí)間片是CPU分配給各個(gè)線程的時(shí)間,這個(gè)時(shí)間片非常短,所以就不得不通過切換線程來執(zhí)行(時(shí)間片一般是幾十毫秒)

當(dāng)前任務(wù)執(zhí)行一個(gè)時(shí)間片后,會(huì)切換到下一個(gè)任務(wù),但是,在切換前會(huì)保存上一個(gè)任務(wù)的狀態(tài),這樣的話下次這條線程獲取到時(shí)間片之后就可以恢復(fù)這個(gè)任務(wù)的狀態(tài)

協(xié)程

協(xié)程說通俗一點(diǎn)就是由線程調(diào)度的線程,操作系統(tǒng)創(chuàng)建一個(gè)進(jìn)程,進(jìn)程再創(chuàng)建若干個(gè)線程并行,線程的切換由操作系統(tǒng)負(fù)責(zé)調(diào)度,Java語言等線程其實(shí)與操作系統(tǒng)線程是1:1的關(guān)系,每個(gè)線程都有自己的Stack,Java在64位操作系統(tǒng)默默人stack大小為1024kb,所以一個(gè)進(jìn)程也是不能夠開啟上萬個(gè)線程的

基于J2EE項(xiàng)目都是基于每個(gè)請(qǐng)求占用一個(gè)線程去完成完整的業(yè)務(wù)邏輯,(包括事務(wù))。所以系統(tǒng)的吞吐能力取決于每個(gè)線程的操作耗時(shí)。如果遇到很耗時(shí)的I/O行為,則整個(gè)系統(tǒng)的吞吐立刻下降,比如JDBC是同步阻塞的,這也是為什么很多人都說數(shù)據(jù)庫是瓶頸的原因。這里的耗時(shí)其實(shí)是讓CPU一直在等待I/O返回,說白了線程根本沒有利用CPU去做運(yùn)算,而是處于空轉(zhuǎn)狀態(tài)。

Java的JDK里有封裝很好的ThreadPool,可以用來管理大量的線程生命周期,但是本質(zhì)上還是不能很好的解決線程數(shù)量的問題,以及線程空轉(zhuǎn)占用CPU資源的問題。

先階段行業(yè)里的比較流行的解決方案之一就是單線程加上異步回調(diào)。其代表派是node.js以及Java里的新秀Vert.x。他們的核心思想是一樣的,遇到需要進(jìn)行I/O操作的地方,就直接讓出CPU資源,然后注冊(cè)一個(gè)回調(diào)函數(shù),其他邏輯則繼續(xù)往下走,I/O結(jié)束后帶著結(jié)果向事件隊(duì)列里插入執(zhí)行結(jié)果,然后由事件調(diào)度器調(diào)度回調(diào)函數(shù),傳入結(jié)果。

協(xié)程的本質(zhì)上其實(shí)還是和上面的方法一樣,只不過他的核心點(diǎn)在于由他進(jìn)行調(diào)度,遇到阻塞操作,立刻yield掉,并且記錄當(dāng)前棧上的數(shù)據(jù),阻塞完后立刻再找一個(gè)線程恢復(fù)棧并把阻塞的結(jié)果放到這個(gè)線程上去跑,這樣看上去好像跟寫同步代碼沒有任何差別,這整個(gè)流程可以稱為coroutine,而跑在由coroutine負(fù)責(zé)調(diào)度的線程稱為Fiber。比如Golang里的 go關(guān)鍵字其實(shí)就是負(fù)責(zé)開啟一個(gè)Fiber,讓func邏輯跑在上面。而這一切都是發(fā)生的用戶態(tài)上,沒有發(fā)生在內(nèi)核態(tài)上,也就是說沒有切換上下文的開銷。

Java線程調(diào)度

JVM必須維護(hù)一個(gè)有優(yōu)先權(quán),基于優(yōu)先級(jí)的調(diào)度模式,優(yōu)先級(jí)的值很重要,因?yàn)镴ava虛擬機(jī)和下層的操作系統(tǒng)之間的約定是操作系統(tǒng)必須選擇有最高優(yōu)先權(quán)的Java線程運(yùn)行,所以我們說Java實(shí)現(xiàn)了一個(gè)基于優(yōu)先權(quán)的調(diào)度程序該調(diào)度程序使用一種有優(yōu)先權(quán)的方式實(shí)現(xiàn),這意味著當(dāng)一個(gè)有更高優(yōu)先權(quán)的線程到來時(shí),無論低優(yōu)先級(jí)的線程是否在運(yùn)行,都會(huì)中斷(搶占)它(JVM會(huì)這么做)。這個(gè)約定對(duì)于操作系統(tǒng)來說并不總是這樣,這意味著操作系統(tǒng)有時(shí)可能會(huì)選擇運(yùn)行一個(gè)更低優(yōu)先級(jí)的線程。

yield()方法

理論上,yield意味著放手,放棄,投降。一個(gè)調(diào)用yield()方法的線程告訴虛擬機(jī)它樂意讓其他線程占用自己的位置。這表明該線程沒有在做一些緊急的事情。注意,這僅是一個(gè)暗示,并不能保證不會(huì)產(chǎn)生任何影響。

/**

* A hint to the scheduler that the current thread is willing to yield its current use of a processor. The scheduler is free to ignore

* this hint. Yield is a heuristic attempt to improve relative progression between threads that would otherwise over-utilize a CPU.

* Its use should be combined with detailed profiling and benchmarking to ensure that it actually has the desired effect.

*/

public static native void yield();

Yield是一個(gè)靜態(tài)的本地(native)方法

Yield告訴當(dāng)前正在執(zhí)行的線程把運(yùn)行機(jī)會(huì)交給線程池中擁有相同優(yōu)先級(jí)的線程。

Yield不能保證使得當(dāng)前正在運(yùn)行的線程迅速轉(zhuǎn)換到可運(yùn)行的狀態(tài)

它僅能使一個(gè)線程從運(yùn)行狀態(tài)轉(zhuǎn)到可運(yùn)行狀態(tài),而不是等待或阻塞狀態(tài)

join()方法

如果一個(gè)線程A執(zhí)行了thread.join()方法目的是,當(dāng)前線程A等待thread線程終止之后才從thread.join()返回,

/**

* Waits for this thread to die.

*

*

An invocation of this method behaves in exactly the same

* way as the invocation

*

*

* {@linkplain #join(long) join}{@code (0)}

*

*

* @throws InterruptedException

* if any thread has interrupted the current thread. The

* interrupted status of the current thread is

* cleared when this exception is thrown.

*/

public final void join() throws InterruptedException {

join(0);

}

/**

* Waits at most {@code millis} milliseconds for this thread to

* die. A timeout of {@code 0} means to wait forever.

*

*

This implementation uses a loop of {@code this.wait} calls

* conditioned on {@code this.isAlive}. As a thread terminates the

* {@code this.notifyAll} method is invoked. It is recommended that

* applications not use {@code wait}, {@code notify}, or

* {@code notifyAll} on {@code Thread} instances.

*

* @param millis

* the time to wait in milliseconds

*

* @throws IllegalArgumentException

* if the value of {@code millis} is negative

*

* @throws InterruptedException

* if any thread has interrupted the current thread. The

* interrupted status of the current thread is

* cleared when this exception is thrown.

*/

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;

}

}

}

如何減少上下文切換

無鎖并發(fā)編程,多線程競(jìng)爭(zhēng)鎖的時(shí)候,會(huì)引起上下文切換,如將數(shù)據(jù)的ID按照Hash算法取模分段,不同線程處理不同段的數(shù)據(jù)

CAS算法,Java的Atomic包下使用的同步類都是使用CAS和Volatile實(shí)現(xiàn)的無鎖

線程數(shù)量的控制

協(xié)程:單線程內(nèi)實(shí)現(xiàn)多任務(wù)的調(diào)度,在單線程中維持多個(gè)任務(wù)間的切換

如何避免死鎖

避免一個(gè)線程同時(shí)獲得多個(gè)鎖

避免一個(gè)線程在鎖內(nèi)同時(shí)占用多個(gè)資源,盡量保證每個(gè)鎖只占用一個(gè)資源

嘗試使用定時(shí)鎖,tryLock(time)代替內(nèi)部鎖的機(jī)制

對(duì)于數(shù)據(jù)庫來說,加鎖和解鎖必須在同一條連接中,否則將會(huì)出現(xiàn)問題

與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的Java wait forever_彻底搞清楚Java并发 (一) 基础的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。