2013-03-27 3 views
1

Моя тестовая программа запрашивает строку и печатает ее каждые 2 секунды. Я уже кое-что прочитал о модели памяти Java или о том, как потоки не сразу обновляют свои переменные в основной памяти.Как обновить сразу общие переменные между потоками

Я пробовал с volatile и static атрибутами. Синхронизация кодовых блоков, в которых была изменена переменная 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

У вас есть два основных вопроса:

  • Для одной строки являются неизменными, и поэтому вы не можете изменить состояние переменной String, такие как символы которые составляют его, после его создания, и
  • Вы назначаете две ссылочные переменные одному и тому же объекту, но ожидаете, что одна переменная изменит свое назначение если назначение другой переменной изменяется, и это не так, как работают ссылочные переменные 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' не изменен, но' Integer' был. Быстрый поиск показал мне, что JAVA пытается избежать изменчивых объектов. – dinigo

+0

@ demil133: обратите внимание, что ваш код может работать с примитивами, и поэтому нет необходимости их обертывать. Java умна, чтобы избежать изменчивых объектов для строк или примитивных объектов-оберток, поскольку это избавляет вас от множества неприятностей. –

+0

с 'int/boolean/char' и так? Я уже пробовал. Но я раньше ошибался. Я попробую еще раз. – dinigo

Смежные вопросы