我确认通常可以通过这种方式创建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的“在构造函数中做太多工作”的示例。

09-10 05:22
查看更多