gpt4 book ai didi

java - 没有看到静态类变量从在单独线程中运行的同一包中的另一个类更改

转载 作者:行者123 更新时间:2023-12-01 18:32:19 24 4
gpt4 key购买 nike

我有一个 GUI 类,按下按钮后,它会为私有(private)静态类变量分配一个值——我们称之为 strX。

类 GUI 的构造函数还实例化一个子类(在同一包中)。该子类实现Runnable,并启动一个线程。线程中有一个无限循环,它不断查询 strX 的值,直到它不再为 null。查询是通过调用 GUI 类中的 getter 方法来完成的。

我注意到,即使在按下按钮并将 strX 设置为某个非空值之后,子类中的查询也仅产生 null。

我是 Java 新手,我开始怀疑我的理解是否有缺陷。

我已阅读 Java: cannot access static variable from a different class in the same package及其 4 个答案,解决了与变量名称冲突有关的情况。我的情况肯定不是这样的。我想做的就是使用 getter 方法从子类获取类变量。

如果我的问题的任何方面需要澄清,请告诉我。我会发布代码,但它很长,可能会增加困惑。

后续

好的,首先,我要感谢 Darren Gilroy 的详细回答和代码片段。这消除了我心中的一些困惑,但我仍然有问题。因此,为了清晰起见,我决定创建一个简单的精简版本的代码,并开始测试它。这个简单的 GUI 类有两个按钮,一个称为“Only Instantiate”,另一个称为“Only Instantiate”“设置值并实例化”。

  1. 当您按下“仅实例化”时,它会创建另一个名为 PeekAtGUI 的类的实例。在 PeekAtGUI 内部,启动了一个线程。线程调用GUI的静态getter方法来获取GUI中静态类变量strX的当前值。

  2. 当您按下“设置值并实例化”按钮时,它首先将 strX 的值设置为新值,然后实例化 PeekAtGUI。

请注意,在调试时,我注释掉了其中一个或另一个实例。

底线是这样的——当我尝试先实例化,然后按另一个按钮设置新值时,PeekAtGUI 似乎没有获取更新的值。但是,如果我通过按一下按钮来实例化并设置值,那么这一切似乎都神奇地起作用了。

不确定发生了什么,任何澄清将不胜感激。再次感谢。

这是代码-

类 GUI

package intercom;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class GUI {

private JFrame frame;
private static volatile String strX = "";

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GUI window = new GUI();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}

/**
* Create the application.
*/
public GUI() {
initialize();
}

/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
panel.setLayout(null);

JButton btnSet = new JButton("Set Value and Instantiate");
btnSet.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setVal(strX+"+");
new PeekAtGUI(); // When PeekAtGUI instantiated here, it is able to get the new strX
}
});
btnSet.setBounds(106, 94, 224, 23);
panel.add(btnSet);

JButton btnStart = new JButton("Only Instantiate");
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//new PeekAtGUI(); // When PeekAtGUI is instantiated here, it is NOT able to get the new strX
}
});
btnStart.setBounds(106, 39, 224, 23);
panel.add(btnStart);
}

public static synchronized void setVal(String str){
strX = str;
GUI.class.notifyAll();
}
public static synchronized String getVal(){
return strX;
}
}

PeekAtGUI 类

package intercom;

public class PeekAtGUI implements Runnable{

private static String msg = "";
private boolean done = false;
public PeekAtGUI() {
Thread r = new Thread(this, "PeekAtGUI Thread");
r.start();
}



public void run() {
while (done == false){
try {getMsg();}catch (InterruptedException e) {e.printStackTrace();}
System.out.println("Reporting value of strX from PeekAtGUI: " + msg);
}
}

private static synchronized void getMsg() throws InterruptedException{
while((msg==GUI.getVal())){PeekAtGUI.class.wait();}
msg = GUI.getVal();
}
}

最佳答案

在尝试跨线程共享数据之前,您需要花一些时间了解 how Java treats various types of data when it comes to threading :

Even if you access a static value through multiple threads, each thread can have its local cached copy! To avoid this you can declare the variable as static volatile and this will force the thread to read each time the global value.

However, volatile is not a substitute for proper synchronisation! For instance ...

从事情的声音来看,您每次都会读取线程的缓存值 - 您可能会或可能不会看到更改,并且尝试使您的程序可预测地执行将是一个严重头痛。阅读 stivlo's answer 的其余部分,并考虑为线程之间的通信提供更合理的设计。

关于java - 没有看到静态类变量从在单独线程中运行的同一包中的另一个类更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23619936/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com