Создание потока Java стоит дорого, потому что в нем задействовано немало работы:
- Большой блок памяти должен быть выделен и инициализирован для стека потоков.
- Системные вызовы должны быть сделаны для создания / регистрации собственного потока с хост-ОС.
- Дескрипторы должны быть созданы, инициализированы и добавлены во внутренние структуры данных JVM.
Это также дорого в том смысле, что поток связывает ресурсы, пока он жив; например, стек потоков, любые объекты, достижимые из стека, дескрипторы потоков JVM, дескрипторы собственных потоков ОС.
Стоимость всех этих вещей зависит от платформы, но они недешевы для любой платформы Java, с которой я когда-либо сталкивался.
Поиск Google нашел мне старый тест, который показывает скорость создания потоков ~ 4000 в секунду на Sun Java 1.4.1 на двухпроцессорном старом процессоре 2002 года Xeon под управлением винтажного Linux 2002 года. Более современная платформа даст лучшие цифры ... и я не могу комментировать методологию ... но, по крайней мере, она дает оценку того, насколько дорогостоящим будет создание потоков.
Бенчмаркинг Питера Лоури показывает, что в наши дни создание потоков значительно быстрее в абсолютном выражении, но неясно, насколько это связано с улучшениями в Java и / или ОС ... или более высокими скоростями процессора. Но его числа по- прежнему указывают на 150-кратное улучшение, если вы используете пул потоков вместо создания / запуска нового потока каждый раз. (И он подчеркивает, что это все относительно ...)
(Выше предполагается, что «собственные потоки», а не «зеленые потоки», но все современные JVM используют собственные потоки из соображений производительности. Создание зеленых потоков возможно дешевле, но вы платите за это в других областях.)
Я немного покопался, чтобы увидеть, как действительно выделяется стек потока Java. В случае OpenJDK 6 в Linux стек потоков выделяется вызовом, pthread_create
который создает собственный поток. (JVM не проходит pthread_create
предварительно выделенный стек.)
Затем внутри pthread_create
стека выделяется вызов mmap
следующим образом:
mmap(0, attr.__stacksize,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
В соответствии с man mmap
этим MAP_ANONYMOUS
флаг вызывает инициализацию памяти в ноль.
Таким образом, даже если может быть необязательно, чтобы новые стеки потоков Java обнулялись (в соответствии со спецификацией JVM), на практике (по крайней мере, с OpenJDK 6 в Linux) они обнуляются.