Вопрос по multithreading, java – Почему плохая практика - создавать новый поток для конструкторов? [Дубликат]

2

Possible Duplicate:
Java: Why not to start a thread in the constructor? How to terminate?

Я привык бегатьFindBugs в моем коде, чтобы найти ошибки или плохую практику. Сегодня он жалуется на то, что я запускаю поток в конструкторе класса.

Это действительно плохо? Не могли бы вы объяснить мне, почему?

По крайней мере, безопасно, если мой класс окончательный?

EDIT:

Поток реализован как внутренний класс и использует только поля основного класса, уже инициализированные при его запуске:

public final class SingletonOuter {
    private static SingletonOuter ourInstance = new SingletonOuter();

    public static SingletonOuter getInstance() {
        return ourInstance;
    }

    private final SomeOtherClass aField;

    private SingletonOuter() {
        aField=new SomeOtherClass(); 
        thread=new InnerThread();
        thread.start();
    }

    private boolean pleaseStop;

    private synchronized boolean askedStop(){return pleaseStop;}
    public synchronized void stop(){
        pleaseStop=true;  
    }

    private final InnerThread thread ;
    private class InnerThread extends Thread{
        @Override public void run() {
            //do stuff with aField until askedStop()
        }
    }

}

EDIT:

Наконец, я перемещаю начало потока в метод getInstance, чтобы избежать возможности появления будущих ошибок:

public final class SingletonOuter {
        private static SingletonOuter ourInstance

        public static SingletonOuter getInstance() {
            if (ourInstance==null){
                ourInstance= = new SingletonOuter();
                ourInstance.thread.start();
            }

            return ourInstance;
        }

        private final SomeOtherClass aField;

        private SingletonOuter() {
            aField=new SomeOtherClass(); 
            thread=new InnerThread();

        }
        ...
Я отредактировал свой ответ теперь, когда мы видим код. Вы в порядке, но только потому, чтоaField являетсяfinal, По крайней мере, большой комментарий оправдан. Увидеть ниже. Gray
Заданный вопрос не является точным дублированием: я не избегаю этого и не спрашиваю, как остановить мою ветку. Я добавлю код, чтобы уточнить Andrea Parodi
мой ответ был неверным. Хотя окончательные поля гарантированно инициализируются при возврате из конструктора, если вы разветвляете свой поток в конструкторе, нет гарантии, чтоafield будет правильно инициализирован. Я изменил свой ответ. Увидеть:cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#finalRight Gray

Ваш Ответ

3   ответа
2

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

Вот ссылка на хорошую статью об этомhttp://www.ibm.com/developerworks/java/library/j-jtp0618/index.html

Error: User Rate Limit Exceeded Andrea Parodi
Error: User Rate Limit Exceeded
5

Findbugs предупреждает вас о проблеме с возможностью переупорядочивания команд вокруг строительства объекта. Хотя пространство памяти для нового объекта выделено, нет гарантии, что какое-либо из полей было инициализировано к тому времени, когдаInnerThread был начат Хотяfinal поляwill инициализироваться до завершения конструктора, нет гарантии, что еслиInnerThread начинает использовать (например)aField когда это начнется, это будет инициализировано. Компилятор Java делает это по соображениям производительности. Также имеется возможность перенести инициализацию не финальных полей вafter новый экземпляр был возвращен конструктором.

Если вы запускаете новый поток в конструкторе, тогда есть вероятность, что поток будет иметь дело с частично инициализированным объектом. Даже еслиthread.start() это последний оператор в вашем конструкторе, новый поток может получить доступ к частично созданному объекту из-за переупорядочения. Это часть спецификации языка Java.

Вот хорошая ссылка на эту тему:вызов thread.start () в своем собственном конструкторе

Упоминается следующее:

By starting it from within the constructor, you are guaranteed to violate the Java Memory Model guidelines. See Brian Goetz's Safe Construction Techniques for more info.

Edit:

Поскольку ваш код запускает новый поток, который обращается кafieldв соответствии сМодель памяти Java нет никаких гарантий, чтоafield будет правильно инициализирован, когда поток начнет работать.

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

Error: User Rate Limit Exceeded Andrea Parodi
Error: User Rate Limit ExceededguaranteedError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Andrea Parodi
0

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

Error: User Rate Limit Exceeded Andrea Parodi
Error: User Rate Limit ExceededThread t = new Runnable ( ) { public void run ( ) { /*do stuff*/} } ; t . start ( ) ;Error: User Rate Limit Exceedednew Runnable ( ) { { start ( ) ; } public void run ( ) { /*do stuff*/} } ;Error: User Rate Limit Exceeded

Похожие вопросы