Есть ли последствия для производительности при создании потока и его никогда не запускать? - PullRequest
0 голосов
/ 14 ноября 2018

Я работаю над существующей кодовой базой Java, которая имеет объект, который расширяет Thread, а также содержит ряд других свойств и методов, которые относятся к работе самого потока. В предыдущих версиях кодовой базы поток всегда представлял собой фактический, тяжеловесный Thread, который начинался с Thread.start, ожидался с Thread.join и т. П.

В настоящее время я выполняю рефакторинг кодовой базы, и в настоящей версии функциональность Thread объекта не всегда необходима (но сам объект, благодаря другим функциям, содержащимся в объекте; во многих случаях его можно использовать даже когда сам поток не работает). Таким образом, существуют ситуации, в которых приложение создает эти объекты (которые расширяют Thread) и никогда не вызывает .start() для них, просто используя их для своих других свойств и методов.

В будущем приложению может понадобиться создать гораздо больше этих объектов, чем раньше, до такой степени, что мне потенциально придется беспокоиться о производительности. Очевидно, что создание и запуск большого количества реальных потоков будет кошмаром производительности. Относится ли то же самое к Thread объектам, которые никогда не запускаются? То есть требуются ли какие-либо ресурсы операционной системы или большие ресурсы Java исключительно для создания Thread? Или ресурсы используются только тогда, когда Thread фактически .start ed, что делает незапущенные Thread объекты безопасными для использования в количестве? Можно было бы провести рефакторинг кода, чтобы разделить функции, не связанные с многопоточностью, в отдельную функцию, но я не хочу делать большой рефакторинг, если это совершенно бессмысленно.

Я попытался определить ответ на этот вопрос с помощью нескольких поисковых запросов в Интернете, но трудно нацелить запрос, поскольку поисковые системы обычно не могут отличить объект Thread от реального потока Java.

Ответы [ 3 ]

0 голосов
/ 14 ноября 2018

Вы можете создать около 1,5 миллиона таких объектов на ГБ памяти.

import java.util.LinkedList;
import java.util.List;

class A {
    public static void main(String[] args) {
        int count = 0;
        try {
            List<Thread> threads = new LinkedList<>();
            while (true) {
                threads.add(new Thread());
                if (++count % 10000 == 0)
                    System.out.println(count);
            }
        } catch (Error e) {
            System.out.println("Got " + e + " after " + count + " threads");
        }
    }
}

при использовании -Xms1g -Xmx1g для Oracle Java 8 процесс останавливается на отметке

1 GB - 1780000
2 GB - 3560000
6 GB - 10690000

Объект использует немного больше, чем вы могли ожидать от чтения исходного кода, но он по-прежнему около 600 байт каждый.

ПРИМЕЧАНИЕ. Throwable также использует больше памяти, чем вы могли ожидать, читая исходный код Java. Он может быть на 500 - 2000 байт больше в зависимости от размера стека на момент его создания.

0 голосов
/ 14 ноября 2018

Как отмечают другие: производительность здесь не проблема.

Я бы уделил больше внимания подходу "хороший дизайн". Просто не имеет смысла расширять Thread, если вы не собираетесь когда-либо вызывать start(). И вы видите: вы пишете код, чтобы сообщить о своих намерениях.

Расширение потока без использования его в качестве потока, который только сообщает путаницу. Каждый новый читатель вашего кода будет удивляться: «Почему это так?»

Поэтому сосредоточьтесь на том, чтобы перейти к прямолинейному дизайну. И я бы пошел еще дальше: не просто переключайтесь на Runnable и продолжайте использовать потоки. Вместо этого: узнайте об ExecutorServices и о том, как отправлять задачи, а также Futures и все такое.

«Голые железные» нити (и Runnables) подобны 20-летним концепциям. На данный момент у Java есть вещи получше. Итак, если вы действительно серьезно относитесь к улучшению своей кодовой базы: посмотрите на эти новые концепции абстракции, чтобы понять, где их будет целесообразно использовать.

0 голосов
/ 14 ноября 2018

Вы можете реализовать Runnable вместо расширения Thread.

public class MyRunnableClass implements Runnable {

    // Your stuff...

    @Override
    public void run() {
        // Thread-related stuff...
    }

}

Всякий раз, когда вам нужно запустить Object, чтобы вести себя как Thread, просто используйте:

Thread t = new Thread(new MyRunnableClass());
t.start();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...