【问题标题】:Java Thread attributes update automatically?Java Thread属性自动更新?
【发布时间】:2016-02-01 06:55:42
【问题描述】:

我现在真的迷路了。

我有这个Server,它为每个连接的客户端创建一个新的Thread,所以它看起来像这样:

Server.java

...
( new ServerReceiver( toClient, this.connectedPlayersObject ) ).start();
...

toClientObjectOutputStreamthis.connectedPlayerObject 是操作 ArrayList 的对象)

时调用
...
Socket socket = this.serverSocket.accept();
this.connectedPlayersObject.add( thisPlayer );
...

无论如何,在我的 Server.java 中一切正常,但在我上面显示的那个线程中,我有这个:

ServerSender.java ( Thread )

...
private ConnectedPlayers CPO;
private ArrayList<Players> CPL;

public ServerSender( ObjectOutputStream _toClient, ConnectedPlayers _CPO ) {
    super( "ServerSender" );
    this.CPL = _CPO.get(); // returns the whole ArrayList that I have in this moment
    this.CPO = _CPO        // remember the object
}

public void run() {
    while( true ) {
        // here if the Server which starts the Thread is adding something to 
        // this.CPO's ArrayList, this.CPL gets that element inside of it too, why?
        this.printCPLs( this.CPL, this.CPO.get() ); // Prints both ArrayLists Nicely
    }
}
...

即使我从未更新 this.CPL,它们也总是打印相同的更新后的 ArrayList!

正如您在上面看到的,Server.java,每次客户端连接时,它都会将客户端添加到ConnectedPlayers 对象中的ArrayList,所以在线程中,我期待得到正确的ArrayList 时我打电话给.get();,但我在私有属性this.CPLthis.CPO.get(); 上都得到了正确/更新的元素,所以我不知道ArrayList 何时真正从一个状态变为另一个状态

编辑:对象女巫操纵 ArrayList(CPO / connectedPlayersObject):

ConnectedPlayers.java    

public class ConnectedPlayers implements Serializable {

    private static final long serialVersionUID = -3225902114667506709L;

    private ArrayList<Player> connectedPlayers;

    public ConnectedPlayers() {
        this.connectedPlayers = new ArrayList<Player>();
    }

    public synchronized void add( Player _player ) { this.connectedPlayers.add( _player ); this.notifyChange(); }

    public ArrayList<Player> get() { return this.connectedPlayers; }

    private void notifyChange() {  }

}

【问题讨论】:

  • 对不起,这个很不清楚。 “而且他们总是打印同样的东西,即使我从来没有更新 this.CPL”。如果您从不更新它,它应该保持不变。你是什​​么意思?同时显示更多代码,包括CPLCPO 的声明。
  • Server.java 在客户端从对象CPO 连接到 ArrayList 时添加客户端,该对象具有一些操作该 ArrayList 的方法(例如 .get(); 获取 ArrayList 或 .add(); 添加ArrayList 的客户端)。在线程中,我得到那个对象,我得到当前的 ArrayList 并将其设置为属性CPL,当服务器通过CPO.add(); 向该 ArrayList 添加一些东西时,具有初始 ArrayList 的属性被更新,即使我不不要在线程中更新它。我不知道..老实说如何让它更清楚,我知道它有点乱......
  • @JimGarrison 完全一样,它应该保持不变,但它不会,它会在this.CPO 中的 ArrayList 更新时更新

标签: java multithreading arraylist server client


【解决方案1】:

您的所有代码都保留对同一个ArrayList 对象的引用,因为您从不创建它的副本。因此,当代码的一部分将一个对象添加到ArrayList 时,它对代码中存储对同一ArrayList 的引用的其他地方可见。

如果要创建ArrayList 的副本,请使用new ArrayList&lt;Player&gt;(originalList)

您使用线程的事实在这里无关紧要; Java 中的线程共享相同的内存空间并可以访问相同的对象。将对象分配给线程属性不会自动创建它的副本。

【讨论】:

  • this.CPL = new ArrayList&lt;Player&gt;( this.CPO.get() ) 没有做到这一点,但我明白你告诉我的......我真的不知道如何解决这个问题,我只想知道服务器何时实际更改了 ArrayList (添加或删除元素)并且在我的线程中,当我通过对象将元素添加到 ArrayList 时,我对该 ArrayList 所做的副本仍然会更新..
  • 我什至手动创建了另一个 ArrayList 循环遍历我从 this.CPO.get();并一一添加每个元素..当服务器使用 .add(); 调用该对象时仍然会更新;
  • 根据您显示的代码,这不可能发生。请尝试使用调试器单步执行您的代码。调试器可以向您显示每个对象的身份,因此您可以查看何时使用同一个对象以及何时拥有不同的副本。
  • 是的!是的,就是这样,你是对的,只是我引用了对象内部的同一个 ArrayList,谢谢一百万!让我免于再盯着同一个屏幕一周。