Reputation: 7428
My test program asks for a string and prints it every 2 seconds. I've read some already about java memory model or how threads don't immediately update their variables on the main memory.
I've tried with volatile
and static
attributes. Synchronizing code blocks in which the variable line
was modified. With wait()/notifi()
when the variable was changed and some others. How do I assign line
as a reference and not as value? Am I using the methods I tried wrong? Why can objects stay perfectly synchronized when they act as monitors but they can't be when acting as pointers?
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);
}
}
}
Output:
Thread-0:
asdf
Thread-0:
Thread-0:
Upvotes: 2
Views: 2552
Reputation: 285403
You have two main issues:
In other words, even though you're initially setting the Printer object's line variable to the same reference as the TestSharedVariable's static line variable, changing the TestSharedVariable's static line variable's reference later will have no effect on Printer line variable's reference assignment. This has nothing to do with threading and all to do with understanding reference variables. Think of reference variables like pointers in C or other similar languages. If two variables point to the same object, changing one variable to point to a different object will have no effect on the first variable.
For your code to work, both variables must share a reference to the same mutable object, and you must change the state of the mutable object, not the reference to it.
For e.g.,
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;
}
}
Upvotes: 3