如何在线程之间立即更新共享变量

时间:2013-03-27 02:31:14

标签: java multithreading asynchronous concurrency

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

1 个答案:

答案 0 :(得分:3)

您有两个主要问题:

  • 因为一个字符串是不可变的,所以你不能改变一个String变量的状态,比如构成它的字符,一旦它被创建,
  • 您正在为同一个对象分配两个引用变量,但是如果另一个变量的赋值更改,则期望一个变量更改其赋值,而这不是Java引用变量的工作方式。

换句话说,即使您最初将Printer对象的行变量设置为与TestSharedVariable的静态行变量相同的引用,稍后更改TestSharedVariable的静态行变量的引用也不会影响Printer行变量的引用赋值。这与线程无关,而与理解引用变量有关。想想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;
   }

}