我确认通常可以通过这种方式创建Thread
对象并对其进行跟踪:
ArrayList<MyThreadClass> threads = new ArrayList<>();
MyThreadClass myThread = new Thread();
myThread.start();
threads.add(myThread);
但是,与其显式地进行所有操作,不如将其添加到构造函数中并使其隐式发生呢?
我正在创建一个通用的服务器/客户端程序对,以在未来的网络应用程序中实现,并且我采用了一些实用的捷径。
我创建了一个“ Connection”类来跟踪已连接到服务器的客户端。看起来像这样:
class Connection{
private static ArrayList<Connection> clients = new ArrayList<>();
MyListener listener; //extends Thread
Connection(Socket s){
listener = new MyListener(s)
listener.start();
clients.add(this);
}
}
此类具有静态ArrayList来跟踪所有连接,并且构造函数将每个
new Connection
隐式添加到此列表中,并且还启动了我的侦听器Thread
来接收传入的网络流量。我还有一个
ConnectionListener
服务器正在使用它来接受传入的连接,并为每个连接建立Connection
实例,如下所示:while(true){
//try/catch blocks excluded here for the sake of simplicity
new Connection(serverSocket.accept());
}
也许我只是没有偶然找到正确的代码示例,但我很少(如果有的话)看到这种使用构造函数制作对象并存储其引用的方法。我想知道使用列出的两种情况是否非常规和/或不切实际,并且其中任何一种都可能导致错误。
是非常规/不切实际的:
使用
new MyClass()
而不存储返回的参考?使用实例的构造函数中的
this
关键字将实例添加到列表中?从(孩子的)构造函数中启动
Thread
?在实例的构造函数完成之前引用实例是否会引起问题? (在这种情况下,在构造函数内部)
最佳答案
使用新的MyClass()而不存储返回的引用?
除非您立即在该引用上调用一个方法,否则这有点奇怪-这意味着构造函数具有副作用。通常,您应该尝试避免在构造函数中产生副作用。
这里的副作用是将实例添加到static
列表中。我强烈建议您反对。这是可变的全局状态,并且可能导致各种难以调试的问题以及可测试性降低。
最好有一个工厂来创建Connection
实例,并将其添加到“工厂创建的实例”列表中:
class ConnectionFactory {
List<Connection> createdInstances;
Connection createInstance(Socket socket) {
Connection instance = new Connection(socket);
createdInstances.add(instance);
return instance;
}
}
使用构造器中的this关键字将实例添加到列表中吗?
嗯,这与
在实例的构造函数完成之前引用实例是否会引起问题? (在这种情况下,在构造函数内部)
答案是肯定的,这可能会导致很多问题,尤其是在多线程代码中使用实例时。我建议您阅读《 Java并发实践》,它彻底解决了与泄漏对部分初始化对象的引用有关的问题。
从(孩子的)构造函数中启动线程?
这是Misko Hevery has written an excellent article about的“在构造函数中做太多工作”的示例。