Сколько потоков может поддерживать Java VM?

Сколько потоков может поддерживать Java VM? Это зависит от поставщика? по операционной системе? другие факторы?

15 ответов

Решение

Это зависит от процессора, который вы используете, от операционной системы, от того, что делают другие процессы, от того, какую версию Java вы используете, и от других факторов. Я видел, что сервер Windows имеет> 6500 потоков, прежде чем остановить машину. Конечно, большинство потоков ничего не делали. Как только машина набрала около 6500 потоков (в Java), у всей машины начались проблемы и она стала нестабильной.

Мой опыт показывает, что Java (последние версии) может с удовольствием потреблять столько потоков, сколько сам компьютер может разместить без проблем.

Конечно, у вас должно быть достаточно оперативной памяти, и вы должны запустить Java с достаточным объемом памяти, чтобы делать все, что делают потоки, и иметь стек для каждого потока. Любая машина с современным процессором (последние пару поколений AMD или Intel) и с 1–2 гигабайтами памяти (в зависимости от ОС) может легко поддерживать JVM с тысячами потоков.

Если вам нужен более конкретный ответ, чем этот, лучше всего подать заявку.

Хм, много.

Здесь есть несколько параметров. Конкретная ВМ, плюс обычно на ней также есть параметры времени выполнения. Это в некоторой степени определяется операционной системой: какую поддержку имеет базовая ОС для потоков и какие ограничения она на них накладывает? Если виртуальная машина вообще использует потоки на уровне ОС, то старый добрый красный / зеленый поток.

Что означает "поддержка" - это другой вопрос. Если вы пишете программу на 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();
        }
    }
}

На OS/X 10.5.6 на Intel и Java 6 5 (см. Комментарии) вот что я получил

Новая тема #2547
Новая тема #2548
Новая тема #2549
Не могу создать тему: 5
Новая тема #2550
Исключение в потоке "main" java.lang.OutOfMemoryError: невозможно создать новый собственный поток
        в java.lang.Thread.start0(собственный метод)
        на java.lang.Thread.start(Thread.java:592)
        в DieLikeADog.main(DieLikeADog.java:6)

Прочитав статью Чарли Мартина, мне стало интересно, влияет ли размер кучи на количество потоков, которые вы можете создать, и я был совершенно ошеломлен результатом.

Используя JDK 1.6.0_11 в Vista Home Premium SP1, я выполнил тестовое приложение Чарли с разными размерами кучи, от 2 МБ до 1024 МБ.

Например, чтобы создать кучу объемом 2 МБ, я бы вызвал JVM с аргументами -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

Так что, да, размер кучи определенно имеет значение. Но взаимосвязь между размером кучи и максимальным количеством потоков НЕПРАВИЛЬНО пропорциональна.

Что странно.

Я знаю, что этот вопрос довольно старый, но просто хочу поделиться своими выводами.

Мой ноутбук может обрабатывать программы, которые порождают 25,000 потоки и все эти потоки записывают некоторые данные в базу данных MySql с регулярным интервалом в 2 секунды.

Я запустил эту программу с 10,000 threads за 30 minutes continuously тогда моя система была стабильной, и я мог выполнять другие обычные операции, такие как просмотр, открытие, закрытие других программ и т. д.

С 25,000 threads система slows down но он остается отзывчивым.

С 50,000 threads система stopped responding мгновенно, и мне пришлось перезапустить мою систему вручную.

Мои системные данные следующие:

Processor : Intel core 2 duo 2.13 GHz
RAM : 4GB
OS : Windows 7 Home Premium
JDK Version : 1.6

Перед запуском я устанавливаю аргумент jvm -Xmx2048m,

Надеюсь, поможет.

Абсолютный теоретический максимум, как правило, представляет собой адресное пространство пользователя процесса, разделенное на размер стека потоков (хотя в действительности, если вся ваша память зарезервирована для стеков потоков, у вас не будет работающей программы...).

Так, например, в 32-битной Windows, где каждый процесс имеет адресное пространство пользователя 2 ГБ, что дает каждому потоку размер стека 128 КБ, можно ожидать абсолютного максимума в 16384 потока (=2*1024*1024 / 128). На практике я могу запустить около 13 000 под XP.

Затем, я думаю, вы по существу в том, что (а) вы можете управлять жонглированием таким количеством потоков в вашем коде и не делать явно глупых вещей (например, заставить их всех ждать одного и того же объекта, а затем вызывать notifyAll()...), и (б) может ли операционная система. В принципе, ответом на (б) является "да", если ответом на (а) также является "да".

Кстати, вы можете указать размер стека в конструкторе Thread; для этого вам не нужно (и, вероятно, не следует) возиться с параметрами виртуальной машины.

Поиграв с классом Чарли DieLikeACode, похоже, что размер стека потоков Java - огромная часть того, сколько потоков вы можете создать.

-Xss установить размер стека Java-потока

Например

java -Xss100k DieLikeADog

Но у Java есть интерфейс Executor. Я хотел бы использовать это, вы сможете отправить тысячи задач Runnable, и исполнитель будет обрабатывать эти задачи с фиксированным числом потоков.

Я помню, как слышал лекцию Clojure, в которой он запустил одно из своих приложений на каком-то специализированном компьютере на выставке с тысячами ядер (9000?), И они загрузили их все. К сожалению, я не могу найти ссылку прямо сейчас (помощь?).

Исходя из этого, я думаю, можно с уверенностью сказать, что аппаратные средства и ваш код являются ограничивающими факторами, а не JVM.

При использовании Virtual Threads (предварительная версия была представлена ​​в JDK 19, а завершена в JDK 21) несколько человек сообщили о запуске более 10 миллионов потоков.

Вот JEP для получения дополнительной информации: https://openjdk.org/jeps/444 .

Дополнительная информация для современных (systemd) систем Linux.

Есть много ресурсов об этом значения, которые могут потребоваться настроить (например, Как увеличить максимальное количество потоков JVM (Linux 64bit)); однако новый предел налагается через ограничение systemd "TasksMax", которое устанавливает pids.max для cgroup.

Для сеансов входа в систему значение UserTasksMax по умолчанию составляет 33% от ограничения ядра pids_max (обычно 12 288) и может быть переопределено в /etc/systemd/logind.conf.

Для сервисов DefaultTasksMax по умолчанию составляет 15% от ограничения ядра pids_max (обычно 4915). Вы можете переопределить его для службы, установив TasksMax в "systemctl edit" или обновив DefaultTasksMax в /etc/systemd/system.conf

когда я исследовал эту тему на своем ноутбуке с процессором Samsung AMD объемом 2 ГБ, работающим под управлением Trisquel linux (Ubuntu 18.04). Он может управлять 9534 потоками, а затем генерировать своеобразное исключение.

       at java.base/java.lang.Thread.start0(Native Method)
at java.base/java.lang.Thread.start(Thread.java:803)
at Main.main(Main.java:11)

код:

           public class MultithreadingRunnable implements Runnable {
         public void run(){
             System.out.println("ThreadID " +  Thread.currentThread().getId());
        }
 }



public class Main {
    public static void main(String[] ars){

    for(int i = 0;i<10000;i++){
        Thread mr = new Thread(new MultithreadingRunnable());
        mr.start();
    }
       }

    }

Год 2017... Класс DieLikeADog.

Новый поток #92459 Исключение в потоке "main" java.lang.OutOfMemoryError: невозможно создать новый собственный поток

i7-7700 16 ГБ оперативной памяти

Максимальное количество потоков зависит от следующих вещей:

  • Конфигурация оборудования, как микропроцессор, RAM.
  • Операционная система вроде 32-битной или 64-битной
  • Код внутри метода run. Если код внутри метода run огромен, то однопоточному объекту будет требоваться больше памяти
  • По крайней мере, в Mac OS X 10.6 32bit существует ограничение (2560) для операционной системы. Проверьте этот поток stackru.

    Вы можете обрабатывать любое количество потоков; нет предела Я выполнил следующий код во время просмотра фильма и использования NetBeans, и он работал правильно / без остановки машины. Я думаю, что вы можете сохранить даже больше потоков, чем эта программа.

    class A extends Thread {
        public void run() {
            System.out.println("**************started***************");
            for(double i = 0.0; i < 500000000000000000.0; i++) {
                System.gc();
                System.out.println(Thread.currentThread().getName());
            }
            System.out.println("************************finished********************************");
        }
    }
    
    public class Manager {
        public static void main(String[] args) {
            for(double j = 0.0; j < 50000000000.0; j++) {
                A a = new A();
                a.start();
            }
        }
    }
    
    Другие вопросы по тегам