JVM 最多支持多少個線程?

閱讀本文大概需要 2.8 分鐘。

原文:www.jb51.net/article/49087.htm


McGovernTheory 在 StackOverflow 提了這樣一個問題:

Java 虛擬機最多支持多少個線程?跟虛擬機開發商有關麼?跟操作系統呢?還有其他的因素嗎?

▌Eddie 的回答:

這取決於你使用的 CPU,操作系統,其他進程正在做的事情,你使用的 Java 的版本,還有其他的因素。

我曾經見過一臺 Windows 服務器在宕機之前有超過 6500 個線程。當然,大多數線程什麼事情也沒有做。

一旦一臺機器上有差不多 6500 個線程(Java 裏面),機器就會開始出問題,並變得不穩定。

以我的經驗來看,JVM 容納的線程與計算機本身性能是正相關的。

當然了,你要有足夠的本機內存,並且給 Java 分配了足夠的內存,讓每個線程都可以擁有棧(虛擬機棧),可以做任何想做的事情。

任何一臺擁有現代 CPU(AMD 或者是 Intel 最近的幾代)和 1-2G 內存(取決於操作系統)的機器很容易就可以支持有上千個線程的 Java 虛擬機。

如果你需要一個更精確的答案,最好是自己做壓測。


▌Charlie Martin 的回答:

這裏有很多的參數(可以設置)。對於特定的虛擬機,都會有自己的運行時參數。

(最大線程數)一定程度上由操作系統決定的:底層的操作系統要給線程提供哪些支持?施加哪些限制?虛擬機使用的是原生的操作系統的線程還是 red thread 或者 green thread?

操作系統提供的支持是另一個問題。如果你向下面這樣寫Java程序:

class DieLikeADog {      public static void main(String[] argv){          for(;;){             new Thread(new SomeRunaable).start();          }      } }

(不要抱怨語法細節,這纔剛剛開始)那你當然希望能得到成百上千個運行的線程。

但是,創建一個線程的成本是相對較大的,(過多線程)調度的開銷會變得突出。

能否讓這些線程做有用的事情還不確定。

升級版

好了,迫不及待了!下面是我的一個加了點潤色的小的測試程序:

public class DieLikeADog {    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 系統上,Java 5 的輸出如下:

New thread #2547New thread #2548New thread #2549Can't create thread: 5New thread #2550Exception 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 的回覆以後,我很想知道堆內存的大小是否能夠給創建的線程數帶來不同,然後我就被結果驚呆了:在 Vista Home Premium SP1系統上,使用 JDK 1.6.0_11,設置堆內存的大小從 2M 到 1024M 來執行 Charlie 的測試程序。

比如:創建 2M 的堆內存,我使用的虛擬機參數是:-Xms2m -Xmx2m.

下面是我的測試結果:

2 mb --> 5744 threads4 mb --> 5743 threads8 mb --> 5735 threads12 mb --> 5724 threads16 mb --> 5712 threads24 mb --> 5687 threads32 mb --> 5662 threads48 mb --> 5610 threads64 mb --> 5561 threads96 mb --> 5457 threads128 mb --> 5357 threads192 mb --> 5190 threads256 mb --> 5014 threads384 mb --> 4606 threads512 mb --> 4202 threads768 mb --> 3388 threads1024 mb --> 2583 threads

所以,堆的大小確實很重要。但是,堆大小和最大線程數卻是呈反比例關係。

這太詭異了!

▌Neil Coffey 的回答:

絕對理論上的最大線程數是進程的用戶地址空間除以線程棧的大小(現實中,如果內存全部給線程棧使用,就不會有能運行的程序了)。

因此,以 32 位 Windows 系統爲例,每一個進程的用戶地址空間是 2G,假如每個線程棧的大小是 128K,最多會有 16384(=210241024 / 128)個線程。

實際在XP系統上,我發現大約能啓動 13000 個線程。

然後,我認爲,你的問題本質上是:(a)你是否可以在你的代碼中有效的管理許多的線程,不讓他們做很顯然是愚蠢的事情(比如:讓他們在同一個 object 對象上等待隨後被調用 notifyAll()…),(b)操作系統是否可以有效地管理這許多線程。

基本上來說,如果(a)的答案是”yes”的話,(b)的答案也是”yes”。

很巧的是,你可以在Thread的構造函數中設置線程棧的大小,但是,你不需要也不應該把這個和虛擬機參數弄混淆。



·END·

程序員的成長之路

路雖遠,行則必至

本文原發於 同名微信公衆號「程序員的成長之路」,回覆「1024」你懂得,給個讚唄。

回覆 [ 520 ] 領取程序員最佳學習方式

回覆 [ 256 ] 查看 Java 程序員成長規劃

16bbae8bc44559c3?w=500&h=278&f=jpeg&s=27769



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章