【问题标题】:While Loop variable assignment to RunnableWhile循环变量赋值给Runnable
【发布时间】:2019-06-09 20:22:49
【问题描述】:

当每个 Runnable 都应该分配不同的设备时,为什么每个 Runnable 都打印相同的设备?

似乎每个 Runnable 都在使用从 while 循环分配的最后一个设备。如何确保每个 Runnable 从循环中分配一个设备?

Iterator<TaskCard> i = taskManager.getTaskCards().iterator();

while (i.hasNext()) {
    TaskCard taskCard = i.next();
    taskCard.updateTask();
    ReturnInterface<String> returnInterface = new TaskReturnIterface(taskManager, taskCard);
    Task task = taskCard.getTask();
    ProtocolInterface selectedProtocol = task.getDevice().getSelectedProtocol();
    selectedProtocol.setTask(task);
    selectedProtocol.setReturnInterface(returnInterface);

    SwingUtilities.invokeLater(new Runnable() {
        final ProtocolInterface mySelectedProtocol=selectedProtocol;
        @Override
        public void run() {  
            System.out.println("[Taskmanager.TaskReturnInterface.actionPerformed.RUN()]selectedProtocol device= " + mySelectedProtocol.getDevice());
        }
    });

}

以下是 wsa 请求的协议接口代码。

public abstract class ProtocolInterface<N> implements Callable<ReturnInterface<N>>, Serializable{

protected DefaultDevice device;
protected String name = "";
protected Task task;
protected Date scheduledDate;
protected ReturnInterface<N> returnInterface;

final private CredentialInterface credential = new CredentialInterface() {
    private String user = "";
    private String password = "";
    private int port = 22;

    @Override
    public String getUser() {
        return user;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public int getPort() {
        return port;
    }

    @Override
    public void setUser(String s) {
        user = s;
    }

    @Override
    public void setPassword(String s) {
        password = s;
    }

    @Override
    public void setPort(int p) {
        port = p;
    }

    @Override
    public DefaultDevice getHost() {
        return device;
    }

    @Override
    public void setHost(DefaultDevice host) {
        System.out.println("[ProtocolInterface].CredentialInterface.setHost() host= "+host);
        device = host;
    }
};

boolean useIP = true;

public ProtocolInterface() {
}

public CredentialInterface getCredential() {
    return credential;
}

public ProtocolInterface(String name, DefaultDevice device) {
    this.name = name;
    this.device = device;
}

public DefaultDevice getDevice() {
    return device;
}

public ReturnInterface<N> getReturnInterface() {
    return returnInterface;
}

public void setReturnInterface(ReturnInterface<N> returnInterface) {
    this.returnInterface = returnInterface;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Task getTask() {
    return task;
}

public void setTask(Task task) {
    this.task = task;
}

public Date getScheduledDate() {
    return scheduledDate;
}

public void setScheduledDate(Date scheduledDate) {
    this.scheduledDate = scheduledDate;
}

public abstract Icon getIcon();

public abstract CredentialForm_Interface getCredentialForm();


@Override
public int hashCode() {
    int hash = 7;
    hash = 47 * hash + Objects.hashCode(this.device);
    hash = 47 * hash + Objects.hashCode(this.name);
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final ProtocolInterface<?> other = (ProtocolInterface<?>) obj;
    if (this.useIP != other.useIP) {
        return false;
    }
    if (!Objects.equals(this.name, other.name)) {
        return false;
    }
    if (!Objects.equals(this.device, other.device)) {
        return false;
    }
    if (!Objects.equals(this.credential, other.credential)) {
        return false;
    }
    return true;
}



@Override
public String toString() {
    return name;
}

}

【问题讨论】:

    标签: java variables runnable final


    【解决方案1】:

    是的,你是对的!您参考协议对象创建Runnableinstance。可以更改此引用,直到 invokeLater 完成此任务。所以你必须复制所需的数据而不是保存参考。

    SwingUtilities.invokeLater(new Runnable() {
            final Device device = selectedProtocol.getDevice();
            @Override
            public void run() {  
                System.out.println("[Taskmanager.TaskReturnInterface.actionPerformed.RUN()]selectedProtocol device= " + device);
            }
        });
    

    【讨论】:

    • 输出还是一样。
    • @JamieSnipes 你能提供DeviceSelectedProtocol 类资源吗?
    • 我假设由于 selectedProtocol 也发生了变化,这可能就是它仍在打印同一设备的原因。
    【解决方案2】:

    试试这个:

    Iterator<TaskCard> i = taskManager.getTaskCards().iterator();
    
    while (i.hasNext()) {
        TaskCard taskCard = i.next();
        taskCard.updateTask();
        ReturnInterface<String> returnInterface = new TaskReturnIterface(taskManager, taskCard);
        Task task = taskCard.getTask();
        final ProtocolInterface selectedProtocol = task.getDevice().getSelectedProtocol();
        selectedProtocol.setTask(task);
        selectedProtocol.setReturnInterface(returnInterface);
    
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {  
                System.out.println("[Taskmanager.TaskReturnInterface.actionPerformed.RUN()]selectedProtocol device= " + selectedProtocol.getDevice());
            }
        });
    }
    

    【讨论】:

      【解决方案3】:

      如果没有关于TaskCard 和其他对象的更多信息,很难说,但你应该尝试声明一些变量final 并尝试打印对象的哈希码,以检查它是否真的相同实例 或语义上相等的不同实例:

      for (Iterator<TaskCard> i = taskManager.getTaskCards().iterator(); i.hasNext();) {
          TaskCard taskCard = i.next();
          taskCard.updateTask();
          ReturnInterface<String> returnInterface = new TaskReturnIterface(taskManager, taskCard);
          Task task = taskCard.getTask();
          // Mark this as "final" so you can use it as is in any internal anonymous class:
          final ProtocolInterface selectedProtocol = task.getDevice().getSelectedProtocol();
          selectedProtocol.setTask(task);
          selectedProtocol.setReturnInterface(returnInterface);
          System.out.println("[1] selectedProtocol device=" + selectedProtocol.getDevice().hashCode());
          SwingUtilities.invokeLater(new Runnable() {
              @Override
              public void run() {  
                  System.out.println("[2] selectedProtocol device=" + selectedProtocol.getDevice().hashCode());
              }
          });
      }
      

      对象之间似乎存在一些联系,它们要么打印相同的输出,要么在后端使用相同的对象。尤其是这部分:

      ProtocolInterface selectedProtocol = task.getDevice().getSelectedProtocol();
      selectedProtocol.setTask(task);
      selectedProtocol.setReturnInterface(returnInterface);
      

      看起来很奇怪,因为selectedProtocol 似乎以某种方式与设备本身绑定到一个任务,那么你必须再次设置它的任务?

      它基本上是在做task.getDevice().getSelectedProtocol().setTask(task),看起来你应该检查一些漏洞......

      此外,SwingUtilities.invokeLater() 是为 GUI 处理保留的,因此您可能希望删除它(除非它正在执行 GUI...)。

      【讨论】:

        猜你喜欢
        • 2011-07-12
        • 1970-01-01
        • 2013-09-25
        • 2013-02-17
        • 2016-01-13
        • 2013-11-15
        • 2011-02-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多