创建线程后创建对象与创建线程时传递对象

时间:2018-11-05 08:51:01

标签: java multithreading

在创建线程后创建对象 (下面的方法A)与在当前线程中创建对象并将其传递给新线程(方法B)之间是否有区别?

方法A:

public class AppA {

    private A app;

    public void run() {
        Runnable runnable = () -> {
            this.app = new A();
        };
        Thread workerA = new Thread(runnable);
        workerA.start();
    }
}

public class A {

    private final EventDispatcher dispatcher;

    A() {
        this.dispatcher = new EventDispatcher();
    }
}

public static void main(String[] args) {
    AppA appA = new AppA();
    appA.run();
}

方法B:

public class AppB {

    private B app;

    public void run() {
        EventDispatcher dispatcher = new EventDispatcher();
        Runnable runnable = () -> {
            this.app = new B(dispatcher);
        };
        Thread workerB = new Thread(runnable);
        workerB.start();
    }
}

public class B {

    private final EventDispatcher dispatcher;

    B(EventDispatcher dispatcher) {
        if (dispatcher == null) {
            throw new NullPointerException();
        }
        this.dispatcher = dispatcher;
    }
}

public static void main(String[] args) {
    AppB appB = new AppB();
    appB.run();
}
    在单个线程中创建的
  • App对象。
  • app.run()从单线程调用。

3 个答案:

答案 0 :(得分:2)

我相信,如果您不将同一对象用于其他用途(可以将其传递到其他线程),也没有任何区别。就像基本的OOP一样-您应该在最窄的范围内定义对象。成为线程没有区别。因此,如果您想在线程外部使用它-在外部创建它。否则,在线程中创建它。

答案 1 :(得分:1)

主要是口味问题。但是在方法A中,您具有更好的封装。如果您不需要访问线程外部的调度程序,则最好内联创建它。 但是,如果确实需要访问权限,或者创建了需要单个调度程序的多个线程,则最好通过构造函数将其注入。

Ergo:这取决于...

答案 2 :(得分:1)

在此示例中,差异纯粹是风格上的。但我认为版本A更好,因为:

  • 版本A更简单
  • 正在创建类的AppB中不需要/不需要使用传递给构造函数的对象(在版本B中),因此版本B中的附加复杂性没有实际用途。 / li>

但是假设您需要通过Runnable通过将参数从父线程传递给子线程,那么这样做肯定会更好版本B的方式比其他方式。

例如,假设您要将StringBuilder 1 从主线程传递给子线程:

  • 版本B的方法不需要执行任何同步就可以完成传输。在父线程中对Thread.start()的调用与子线程中对Runnable.run()的相应调用之间有一个 happens-before 。这样可以确保子线程将看到StringBuilder 2

  • 的状态
  • 如果Runnable执行到父线程的回调以拾取StringBuilder之后父线程可能创建的start(),则您需要使用某种形式同步例如同步方法。

  • 如果父线程要在StringBuilder调用之后主动传递start()(例如,通过调用Runnable对象上的setter),则您需要同时进行同步和某种协调;例如子线程可能需要等待将对象传递给它。


1-在本示例中选择此类,因为它不是线程安全的。

2-这假设调用“ start()”之后,“主”线程没有更改缓冲区!