Java虛擬機(jī)最多支持多少個(gè)線程的探討
McGovernTheory在StackOverflow提了這樣一個(gè)問(wèn)題:
Java虛擬機(jī)最多支持多少個(gè)線程?跟虛擬機(jī)開(kāi)發(fā)商有關(guān)么?跟操作系統(tǒng)呢?還有其他的因素嗎?
Eddie的回答:
這取決于你使用的CPU,操作系統(tǒng),其他進(jìn)程正在做的事情,你使用的Java的版本,還有其他的因素。我曾經(jīng)見(jiàn)過(guò)一臺(tái)Windows服務(wù)器在宕機(jī)之前有超過(guò)6500個(gè)線程。當(dāng)然,大多數(shù)線程什么事情也沒(méi)有做。一旦一臺(tái)機(jī)器上有差不多6500個(gè)線程(Java里面),機(jī)器就會(huì)開(kāi)始出問(wèn)題,并變得不穩(wěn)定。
以我的經(jīng)驗(yàn)來(lái)看,JVM容納的線程與計(jì)算機(jī)本身性能是正相關(guān)的。
當(dāng)然了,你要有足夠的本機(jī)內(nèi)存,并且給Java分配了足夠的內(nèi)存,讓每個(gè)線程都可以擁有棧(虛擬機(jī)棧),可以做任何想做的事情。任何一臺(tái)擁有現(xiàn)代CPU(AMD或者是Intel最近的幾代)和1-2G內(nèi)存(取決于操作系統(tǒng))的機(jī)器很容易就可以支持有上千個(gè)線程的Java虛擬機(jī)。
如果你需要一個(gè)更精確的答案,最好是自己做壓測(cè)。
Charlie Martin的回答:
這里有很多的參數(shù)(可以設(shè)置)。對(duì)于特定的虛擬機(jī),都會(huì)有自己的運(yùn)行時(shí)參數(shù)。(最大線程數(shù))一定程度上由操作系統(tǒng)決定的:底層的操作系統(tǒng)要給線程提供哪些支持?施加哪些限制?虛擬機(jī)使用的是原生的操作系統(tǒng)的線程還是red thread或者green thread?
操作系統(tǒng)提供的支持是另一個(gè)問(wèn)題。如果你向下面這樣寫(xiě)Java程序:
class DieLikeADog {
public static void main(String[] argv){
for(;;){
new Thread(new SomeRunaable).start();
}
}
}
(不要抱怨語(yǔ)法細(xì)節(jié),這才剛剛開(kāi)始)那你當(dāng)然希望能得到成百上千個(gè)運(yùn)行的線程。但是,創(chuàng)建一個(gè)線程的成本是相對(duì)較大的,(過(guò)多線程)調(diào)度的開(kāi)銷會(huì)變得突出。能否讓這些線程做有用的事情還不確定。
升級(jí)版
好了,迫不及待了!下面是我的一個(gè)加了點(diǎn)潤(rùn)色的小的測(cè)試程序:
private static Object s = new Object();
private static int count = 0;
public static void main(String[] argv){
for(;;){
new Thread(new Runnable(){
public void run(){
synchronized(s){
count += 1;
System.err.println("New thread #"+count);
}
for(;;){
try {
Thread.sleep(1000);
} catch (Exception e){
System.err.println(e);
}
}
}
}).start();
}
}
}
在Intel的OS/X 10.5.6系統(tǒng)上,Java 5的輸出如下:
New thread #2547
New thread #2548
New thread #2549
Can't create thread: 5
New thread #2550
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:592)
at DieLikeADog.main(DieLikeADog.java:6)
benjismith的回答:
讀了Charlie Martin的回復(fù)以后,我很想知道堆內(nèi)存的大小是否能夠給創(chuàng)建的線程數(shù)帶來(lái)不同,然后我就被結(jié)果驚呆了:在Vista Home Premium SP1系統(tǒng)上,使用JDK 1.6.0_11,設(shè)置堆內(nèi)存的大小從2M到1024M來(lái)執(zhí)行Charlie的測(cè)試程序。比如:創(chuàng)建2M的堆內(nèi)存,我使用的虛擬機(jī)參數(shù)是:-Xms2m -Xmx2m.
下面是我的測(cè)試結(jié)果:
4 mb --> 5743 threads
8 mb --> 5735 threads
12 mb --> 5724 threads
16 mb --> 5712 threads
24 mb --> 5687 threads
32 mb --> 5662 threads
48 mb --> 5610 threads
64 mb --> 5561 threads
96 mb --> 5457 threads
128 mb --> 5357 threads
192 mb --> 5190 threads
256 mb --> 5014 threads
384 mb --> 4606 threads
512 mb --> 4202 threads
768 mb --> 3388 threads
1024 mb --> 2583 threads
所以,堆的大小確實(shí)很重要。但是,堆大小和最大線程數(shù)卻是呈反比例關(guān)系。
這太詭異了!
Neil Coffey的回答:
絕對(duì)理論上的最大線程數(shù)是進(jìn)程的用戶地址空間除以線程棧的大?。ìF(xiàn)實(shí)中,如果內(nèi)存全部給線程棧使用,就不會(huì)有能運(yùn)行的程序了)。因此,以32位Windows系統(tǒng)為例,每一個(gè)進(jìn)程的用戶地址空間是2G,假如每個(gè)線程棧的大小是128K,最多會(huì)有16384(=2*1024*1024 / 128)個(gè)線程。實(shí)際在XP系統(tǒng)上,我發(fā)現(xiàn)大約能啟動(dòng)13000個(gè)線程。
然后,我認(rèn)為,你的問(wèn)題本質(zhì)上是:(a)你是否可以在你的代碼中有效的管理許多的線程,不讓他們做很顯然是愚蠢的事情(比如:讓他們?cè)谕粋€(gè)object對(duì)象上等待隨后被調(diào)用notifyAll()…),(b)操作系統(tǒng)是否可以有效地管理這許多線程。基本上來(lái)說(shuō),如果(a)的答案是”yes”的話,(b)的答案也是”yes”。
很巧的是,你可以在Thread的構(gòu)造函數(shù)中設(shè)置線程棧的大小,但是,你不需要也不應(yīng)該把這個(gè)和虛擬機(jī)參數(shù)弄混淆。
相關(guān)文章
@SpringBootTest 注解報(bào)紅問(wèn)題及解決
這篇文章主要介紹了@SpringBootTest 注解報(bào)紅問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11解決java.util.NoSuchElementException異常的問(wèn)題
這篇文章主要介紹了解決java.util.NoSuchElementException異常的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09詳解JVM類加載機(jī)制及類緩存問(wèn)題的處理方法
這篇文章主要給大家介紹了關(guān)于JVM類加載機(jī)制及類緩存問(wèn)題的處理方法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01@PathVariable注解,讓spring支持參數(shù)帶值功能的案例
這篇文章主要介紹了@PathVariable注解,讓spring支持參數(shù)帶值功能的案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02Spring-data-redis操作redis知識(shí)總結(jié)
這篇文章主要介紹了Spring-data-redis操作redis知識(shí)總結(jié),spring-data-redis是spring-data模塊的一部分,專門用來(lái)支持在spring管理項(xiàng)目對(duì)redis的操作。2017-04-04