为什么在构造函数上创建新线程是一种不好的做法? [英] Why it is bad practice to create a new thread on constructors?

查看:224
本文介绍了为什么在构造函数上创建新线程是一种不好的做法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可能重复:
Java:为什么不开始构造函数中的线程?如何终止?

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

我习惯在我的代码上运行 FindBugs 以便发现错误或不良做法. 今天,它抱怨我在类构造函数中启动线程.

I'm used to run FindBugs on my code in order to find bugs or bad practice. Today it complains on the fact that I'm starting a thread in a class constructor.

真的是一件坏事吗?您能解释一下为什么吗?

Is really a bad thing to do? Could you explain me why?

如果我的课程是期末考试,那至少是安全的?

It is at least safe if my class is final?

编辑:

该线程被实现为一个内部类,并且仅使用启动时已初始化的主类的字段:

The thread is implemented as an inner class and it only uses fields of the main class already initialized when it is started:

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()
        }
    }

}

编辑:

我最终将线程的开始移到了getInstance方法上,以避免引入将来的错误的可能性:

I finally move the start of thread to the getInstance method, to avoid the possibility of introducing future bugs:

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();

        }
        ...

推荐答案

为什么在构造函数上创建新线程是一种不好的做法?

Why it is bad practice to create a new thread on constructors?

Findbugs提醒您有关对象构造的指令重新排序可能性的问题.尽管已为新对象分配了内存空间,但不能保证在启动InnerThread之前已初始化任何字段.尽管final字段 将在构造函数完成之前初始化,但不能保证如果InnerThread在启动时开始使用(例如)aField,它将被初始化. Java编译器出于性能原因执行此操作.它也可以选择将非最终字段的初始化移到构造函数返回新实例后的 上.

Findbugs is alerting you to the problem with instruction reordering possibilities around object construction. Although the memory space for a new object is allocated, there is no guarantee that any of the fields have been initialized by the time your InnerThread has been started. Although the final fields will be initialized before the constructor finishes, there is no guarantee that if InnerThread starts to use (for example) aField when it starts, that it will be initialized. The Java compiler does this for performance reasons. It also has the option to move the initialization of non-final fields to after the new instance has been returned by the constructor.

如果在构造函数中启动新线程,则该线程有可能会处理部分初始化的对象.即使thread.start()是构造函数中的最后一条语句,由于重新排序,新线程也可能正在访问部分构造的对象.这是Java语言规范的一部分.

If you start a new thread in the constructor then there is a chance that the thread will be dealing with a partially initialized object. Even if the thread.start() is the last statement in your constructor, the new thread may be accessing a partially constructed object because of the reordering. This is part of the Java language specification.

关于此主题的链接很好:在内部调用thread.start()自己的构造函数

Here's a good link about the topic: calling thread.start() within its own constructor

它提到以下内容:

通过从构造函数内部启动它,可以确保您违反Java内存模型准则.有关更多信息,请参见 Brian Goetz的安全施工技术.

根据

Since you code is starting a new thread that is accessing afield, according to the Java Memory Model there is no guarantee that afield will be properly initialized when the thread starts to run.

相反,我建议在您的类上添加一个调用thread.start()start()方法.这是一种更好的做法,并且使使用该类的其他类在构造函数中创建线程时也可以看到它.

What I would recommend instead is to add a start() method on your class that calls the thread.start(). This is a better practice and makes it more visible to other classes that are using this class that a thread is created in the constructor.

这篇关于为什么在构造函数上创建新线程是一种不好的做法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆