在创建线程后创建对象 (下面的方法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()
从单线程调用。答案 0 :(得分:2)
我相信,如果您不将同一对象用于其他用途(可以将其传递到其他线程),也没有任何区别。就像基本的OOP一样-您应该在最窄的范围内定义对象。成为线程没有区别。因此,如果您想在线程外部使用它-在外部创建它。否则,在线程中创建它。
答案 1 :(得分:1)
主要是口味问题。但是在方法A
中,您具有更好的封装。如果您不需要访问线程外部的调度程序,则最好内联创建它。
但是,如果确实需要访问权限,或者创建了需要单个调度程序的多个线程,则最好通过构造函数将其注入。
Ergo:这取决于...
答案 2 :(得分:1)
在此示例中,差异纯粹是风格上的。但我认为版本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()
”之后,“主”线程没有更改缓冲区!