以这种方式构造对象是不合常的吗? (关于同一个构造函数的几个问题)

时间:2016-05-23 07:28:38

标签: java multithreading oop constructor static

我通常可以创建Thread对象,并以这种方式跟踪:

ArrayList<MyThreadClass> threads = new ArrayList<>();

MyThreadClass myThread = new Thread();
myThread.start();
threads.add(myThread);

但是,不是将所有显式地,而是将其添加到构造函数并使其发生隐式地

我正在创建一个通用的服务器/客户端程序对,这些程序将在我未来的网络应用程序中实现,我已经采用了一些我觉得切实可行的快捷方式。

我创建了一个“连接”类来跟踪已连接到服务器的客户端。它看起来像这样:

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关键字将实例添加到List中?
  • 从它的(孩子的)构造函数中启动Thread
  • 在构造函数完成之前引用实例会引起问题吗? (在这种情况下,在构造函数本身内)

2 个答案:

答案 0 :(得分:2)

  
      
  1. 使用新的MyClass()而不存储返回的引用?
  2.   

这有点奇怪,除非你立即在该引用上调用一个方法 - 这意味着构造函数有副作用;通常,你应该尽量避免构造函数中的副作用。

这里的副作用是将实例添加到static列表中;我强烈建议不要这样做。这是可变的全局状态,可能导致各种难以调试的问题,以及可测试性降低。

最好让工厂创建Connection个实例,并将其添加到“工厂创建的实例”列表中:

class ConnectionFactory {
  List<Connection> createdInstances;

  Connection createInstance(Socket socket) {
    Connection instance = new Connection(socket);
    createdInstances.add(instance);
    return instance;
  }
}
  
      
  1. 使用构造函数中的this关键字将实例添加到List中?
  2.   

嗯,这与

有关
  
      
  1. 在构造函数完成之前引用实例会引起问题吗? (在这种情况下,在构造函数本身内)
  2.   

答案是,它可能会导致许多问题,尤其是在多线程代码中使用实例时。我建议你阅读 Java Concurrency In Practice ,它可以彻底解决与部分初始化对象泄漏引用相关的问题。

  
      
  1. 从它的(孩子的)构造函数中启动一个线程?
  2.   

这是“在构造函数中做太多工作”的示例,Misko Hevery has written an excellent article about

答案 1 :(得分:0)

这大部分都是风格和品味的问题。但是,(2)到(4)要求在多线程上下文中特别小心,因为另一个控制流可以在当前线程完全构造构造之前获得对正在构造的对象的访问。因此,只有在您建立了对象的一致状态(例如,在构造函数的最后)时,泄漏引用。确保使用单个唯一锁正确同步(2)中使用的数据结构,例如锁定自身或包含类对象。