【问题标题】:Java: Manipulating non-static variable from thread?Java:从线程操作非静态变量?
【发布时间】:2015-02-13 05:26:28
【问题描述】:

我的代码的相关总结是这样的:

public class A {
    String aString;

    public static void main(String[] args) {
        B b = new B();
        new Thread(b).start();
    }
    public static class B implements Runnable {
        public void run() {
            aString = "foo";
        }
    }
}

我有几个月的 Java 编码经验,但 thread 和 dynamic 与 static 对我来说还是比较陌生。为了使线程正确执行,B 类必须是静态的,否则只有线程执行,而不是两者都执行。我的目标显然是让线程在后台执行,以便我在 A 类中可能拥有的其他代码可以同时执行。问题是,如果 B 类是静态的,我无法操作字符串 aString,因为我得到了异常 non-static variable aString cannot be referenced from a static context。

我已经查找了这方面的信息,但我没有找到任何与在线程中解决此问题相关的信息。我的问题是,如何在 B 类中操作 aString 并仍然让线程正常工作(两个类都在运行,而不仅仅是 B 类)?

【问题讨论】:

  • static 与线程无关。如果没有线程,您将遇到同样的问题。例如,new B().run()。或者,如果您刚刚在main 中写了aString = "foo"。

标签: java string multithreading variables static


【解决方案1】:

要使您的示例正常工作,您需要这样的东西:

public class A {
    volatile String aString;

    public static void main(String[] args) throws InterruptedException {
        A a = new A();
        Thread t = new Thread(a.new B());
        t.start();
        t.join(); // wait for t to finish
        System.out.println(a.aString); // prints "foo"
    }

    class B implements Runnable {
        public void run() {
            aString = "foo";
        }
    }
}

解决static 问题很容易 - 请参阅代码了解如何操作。

我希望其余代码有助于说明您在使用线程时需要解决的一些问题。

【讨论】:

  • 问题是,我不想等到线程完成。这只是一个示例代码 - 在实际程序中,我在两个类中都有 while 循环,因此我使用线程。我删除了t.join(),但两个线程仍然没有同时执行。
  • @Xyspade 对于给出的示例,您需要 join() 否则主方法很有可能会在线程执行之前执行 println() - 请记住在线程上调用 start() schedules 它开始,不能保证 when 它会执行。您的问题可能是您需要将字段设置为volatile,以确保它们的值不会缓存在其他线程中 - 并且您的主线程“看到”它们发生了变化。
  • 其实我一直在研究这个问题,问题可能出在其他地方。我会让每个人都更新。再次感谢。
  • 是的,这个解决方案对我有用;我遇到的问题在代码的其他地方。谢谢大家!
【解决方案2】:

B是静态的,所以只存在于类级别,因此看不到其父类的实例变量

public class A {
    String aString;  // <== instance variable

    public static void main(String[] args) {
        B b = new B();
        new Thread(b).start();
    }
    public static class B implements Runnable {  // <== static class
        public void run() {
            aString = "foo";
        }
    }
}

可能的修复。也将 aString 设为静态

public class A {
    static String aString;

可能的修复。使 B 非静态。这是它变得有点奇怪的地方。 B 现在只存在于 A 的实例级别,所以需要先创建一个 A 实例。

public class A {
    String aString;

    public static void main(String[] args) {
        B b = new A().new B();  // <== need to create an A before a B
        new Thread(b).start();
    }
    public class B implements Runnable {
        public void run() {
            aString = "foo";
        }
    }
}

【讨论】:

  • B b = new A().new B(); // &lt;== create via A - 我以前从未见过这个符号 - 很好!
  • 我是在OCJP的书里才发现的,很疯狂不是吗!!?有点像Ruby的Object.new
  • @KevinDay 这是因为您很少需要从外部类外部创建内部类的实例
【解决方案3】:

您要求 B 类的对象实例(您使用 new B() 创建)访问您尚未创建的对象实例的成员变量。在您的代码中,没有创建 B 类的对象。

我认为您可能认为在 A 类中运行 main() 方法会以某种方式实例化 A 类的一个实例 - 事实并非如此。

以下将起作用,因为您正在创建 A 的实例并将其提供给您的 B 实例。

public class A {
    String aString;

    public static void main(String[] args) {
        A a = new A();
        B b = new B(a);
        new Thread(b).start();
    }
    public static class B implements Runnable {
        private final A a;

        public B(A a){
          this.a = a;
        }

        public void run() {
            a.aString = "foo";
        }
    }
}

【讨论】:

    猜你喜欢
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-31
    • 1970-01-01
    • 2012-01-15
    • 1970-01-01
    相关资源
    最近更新 更多