2013-03-27 113 views
1

我的测试程序要求输入一个字符串并每2秒打印一次。我已经阅读了一些关于Java内存模型的知识,或者线程没有立即更新主内存中的变量。我试过volatilestatic属性。同步其中修改了变量line的代码块。用wait()/notifi()当变量和其他一些变化。我如何分配line作为参考而不是价值?我使用了我尝试错误的方法吗?为什么当对象充当监视器时,对象可以保持完全同步,但是当他们作为指针时,他们不可能是对象?如何立即更新线程之间的共享变量

public class TestSharedVariable { 
    static String line= ""; 

    public static void main(String[] args) { 
     // For reading from keyboard 
     Scanner keyboard = new Scanner(System.in); 

     Printer p = new Printer(line); 
     p.start(); 

     // Reads a line from keyboard into the shared variable 
     while(!line.equals("quit")){ 
      line = keyboard.nextLine(); 

     } 
    } 
} 

class Printer extends Thread{ 
    private volatile String line; 

    public Printer(String palabra){ 
     this.line = palabra; 
    } 

    /* Prints the line each 2 sec */ 
    @Override 
    public void run(){ 
     while(!line.equals("quit")){ 
      try { 
       sleep(2000); 
      } catch (InterruptedException e) {e.printStackTrace();} 
      System.out.println(this.getName() + ": " + line); 
     } 
    } 
} 

输出:

Thread-0: 
    asdf 
    Thread-0: 
    Thread-0: 

回答

2

你有两个主要问题:

  • 对于一个字符串是不可改变的,所以你不能改变一个字符串变量的状态,如字符包含它,一旦创建,并且
  • 您正在将两个引用变量分配给同一对象,但期望一个变量更改其分配如果其他变量的赋值发生变化,这不是Java引用变量的工作方式。

换句话说,即使你的打印机对象的行变量最初设置为相同的引用,只要TestSharedVariable的静态行变量,后来改变了TestSharedVariable的静线变量的引用将会对打印机产品线变量的引用没有影响分配。这与线程和处理理解引用变量无关。想想像C或其他类似语言中的指针一样的引用变量。如果两个变量指向同一个对象,将一个变量指向另一个对象将不会影响第一个变量。

为您的代码工作,这两个变量必须共享相同的可变对象的引用,你必须改变可变对象的状态,而不是参考它。

对于例如

import java.util.Scanner; 

public class TestSharedVariable { 
    static volatile MutableObject mutableObject = new MutableObject(); 

    public static void main(String[] args) { 
     // For reading from keyboard 
     Scanner keyboard = new Scanner(System.in); 

     Printer p = new Printer(mutableObject); 
     new Thread(p, "Print thread").start(); 

     // Reads a line from keyboard into the shared variable 
     while (!mutableObject.getData().equals("quit")) { 
     mutableObject.setData(keyboard.nextLine()); 

     } 
    } 
} 

class Printer implements Runnable { 
    private volatile MutableObject mutableObject; 

    public Printer(MutableObject mutableObject) { 
     this.mutableObject = mutableObject; 
    } 

    /* Prints the line each 2 sec */ 
    @Override 
    public void run() { 
     while (!mutableObject.getData().equals("quit")) { 
     try { 
      Thread.sleep(2000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     Thread thread = Thread.currentThread(); 
     System.out.println(thread.getName() + ": " + mutableObject); 
     } 
    } 
} 

class MutableObject { 
    private String data = ""; 

    public String getData() { 
     return data; 
    } 

    public void setData(String data) { 
     this.data = data; 
    } 

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

} 
+0

得到它。感谢超级快速的回答。我把我的变量包装成一个可变的对象。 在第一次我以为'int'不是可变的,但是'整数'是。快速搜索告诉我,JAVA试图避免可变对象。 – dinigo 2013-03-27 03:05:08

+0

@ demil133:请注意,您的代码可以与基元一起使用,因此不需要将它们包装起来。 Java很聪明,可以避免使用Strings或原始包装对象的可变对象,因为它可以避免很多麻烦。 – 2013-03-27 03:07:23

+0

'int/boolean/char'等等?我已经尝试过了。但我以前错了。我会再试一次。 – dinigo 2013-03-27 03:09:34