2

我的测试程序要求输入一个字符串并每 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: 
4

1 回答 1

3

你有两个主要问题:

  • 一方面,字符串是不可变的,因此您无法更改字符串变量的状态,例如组成它的字符,一旦它被创建,并且
  • 您将两个引用变量分配给同一个对象,但希望一个变量在另一个变量的分配更改时更改其分配,这不是 Java 引用变量的工作方式。

换句话说,即使您最初将 Printer 对象的行变量设置为与 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;
   }

}
于 2013-03-27T02:34:28.640 回答