天天看點

JVM最多支援多少個線程?你知道嗎?Java虛拟機最多支援多少個線程?跟虛拟機開發商有關麼?跟作業系統呢?還有其他的因素嗎?最後

關于JVM系列面試知識點總結了一個思維導圖,分享給大家

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 #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的回複以後,我很想知道堆記憶體的大小是否能夠給建立的線程數帶來不同,然後我就被結果驚呆了:在Vista Home Premium SP1系統上,使用JDK 1.6.0_11,設定堆記憶體的大小從2M到1024M來執行Charlie的測試程式。比如:建立2M的堆記憶體,我使用的虛拟機參數是:-Xms2m -Xmx2m.

下面是我的測試結果:

2 mb --> 5744 threads
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
           

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

這太詭異了!

Neil Coffey的回答:

絕對理論上的最大線程數是程序的使用者位址空間除以線程棧的大小(現實中,如果記憶體全部給線程棧使用,就不會有能運作的程式了)。是以,以32位Windows系統為例,每一個程序的使用者位址空間是2G,假如每個線程棧的大小是128K,最多會有16384(=210241024 / 128)個線程。實際在XP系統上,我發現大約能啟動13000個線程。

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

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

最後

關注公衆号:程式員白楠楠, 領取2020最新Java面試題手冊(200多頁PDF文檔)。