volatile 关键字如何确保对象的字段对其他线程可见?
How does volatile keyword ensure an object`s fields are visible to other threads?
public class ObjectPropertiesVolatileTest {
static Cup cup = new Cup();
public static void changeColor() {
cup.setColor("black"); // change color of cup to black
}
public static void main(String[] args) {
cup.setColor("red"); // initialize color of cup as red
for(int i = 0; i < 3; i++) {
new Thread(){
public void run() {
for(int i = 0; i < 10; i++)
System.out.println(Thread.currentThread().getName()
+ " " + i + " is " + cup.getColor());
if(Thread.currentThread().getName().equals("Thread-1"))
changeColor(); // Thread-1 changes the color of cup
for(int i = 0; i < 10; i++)
System.out.println(Thread.currentThread().getName()
+ " " +i + " is " + cup.getColor());
}
}.start();
}
}
}
class Cup {
private volatile String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
我的问题是:如何只使用volatile
关键字而不是使用同步或锁来确保对象cup的字段color
对其他线程可见?
我相信它工作正常。问题是 System.out.println(Thread.currentThread().getName() + " " +i + " is " + cup.getColor());
中的打印、打印语句调用、字符串合并等不同步。
我在您的 getters/setters 中添加了打印语句来记录通话时间:-
public String getColor() {
System.out.println("-------------------------get " + Thread.currentThread().getName() + this.color + " " + System.nanoTime());
return color;
}
public void setColor(String color) {
System.out.println("-------------------------set " + Thread.currentThread().getName() + color + this.color + " " + System.nanoTime());
this.color = color;
}
它打印的内容片段:-
.
.
.
Thread-0 4 is red
-------------------------get Thread-1red 1356826035808750
Thread-1 8 is red
-------------------------get Thread-2red 1356826035425706
Thread-2 2 is red
-------------------------get Thread-1red 1356826035963697
Thread-1 9 is red
-------------------------get Thread-0red 1356826035894581
-------------------------set Thread-1blackred 1356826036165653
-------------------------get Thread-2red 1356826036036858
Thread-2 3 is black
-------------------------get Thread-1black 1356826036219728
Thread-1 0 is black
Thread-0 5 is red
-------------------------get Thread-1black 1356826036402925
Thread-1 1 is black
-------------------------get Thread-2black 1356826036305139
Thread-2 4 is black
-------------------------get Thread-1black 1356826036535236
Thread-1 2 is black
.
.
.
您关心的问题是这一行:-
Thread-0 5 is red
应该是打印了black
吧?
好吧,这个线程在另一个线程更改值之前进入 getter。从这些行可以看出这一点:-
-------------------------get Thread-0red 1356826035894581
-------------------------set Thread-1blackred 1356826036165653
因此它正确读取了值,但与其他线程执行它们正在执行的操作所花费的时间相比,此后完成的处理花费了很长时间。
如果我错了,很高兴有人纠正我。 :)
public class ObjectPropertiesVolatileTest {
static Cup cup = new Cup();
public static void changeColor() {
cup.setColor("black"); // change color of cup to black
}
public static void main(String[] args) {
cup.setColor("red"); // initialize color of cup as red
for(int i = 0; i < 3; i++) {
new Thread(){
public void run() {
for(int i = 0; i < 10; i++)
System.out.println(Thread.currentThread().getName()
+ " " + i + " is " + cup.getColor());
if(Thread.currentThread().getName().equals("Thread-1"))
changeColor(); // Thread-1 changes the color of cup
for(int i = 0; i < 10; i++)
System.out.println(Thread.currentThread().getName()
+ " " +i + " is " + cup.getColor());
}
}.start();
}
}
}
class Cup {
private volatile String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
我的问题是:如何只使用volatile
关键字而不是使用同步或锁来确保对象cup的字段color
对其他线程可见?
我相信它工作正常。问题是 System.out.println(Thread.currentThread().getName() + " " +i + " is " + cup.getColor());
中的打印、打印语句调用、字符串合并等不同步。
我在您的 getters/setters 中添加了打印语句来记录通话时间:-
public String getColor() {
System.out.println("-------------------------get " + Thread.currentThread().getName() + this.color + " " + System.nanoTime());
return color;
}
public void setColor(String color) {
System.out.println("-------------------------set " + Thread.currentThread().getName() + color + this.color + " " + System.nanoTime());
this.color = color;
}
它打印的内容片段:-
.
.
.
Thread-0 4 is red
-------------------------get Thread-1red 1356826035808750
Thread-1 8 is red
-------------------------get Thread-2red 1356826035425706
Thread-2 2 is red
-------------------------get Thread-1red 1356826035963697
Thread-1 9 is red
-------------------------get Thread-0red 1356826035894581
-------------------------set Thread-1blackred 1356826036165653
-------------------------get Thread-2red 1356826036036858
Thread-2 3 is black
-------------------------get Thread-1black 1356826036219728
Thread-1 0 is black
Thread-0 5 is red
-------------------------get Thread-1black 1356826036402925
Thread-1 1 is black
-------------------------get Thread-2black 1356826036305139
Thread-2 4 is black
-------------------------get Thread-1black 1356826036535236
Thread-1 2 is black
.
.
.
您关心的问题是这一行:-
Thread-0 5 is red
应该是打印了black
吧?
好吧,这个线程在另一个线程更改值之前进入 getter。从这些行可以看出这一点:-
-------------------------get Thread-0red 1356826035894581
-------------------------set Thread-1blackred 1356826036165653
因此它正确读取了值,但与其他线程执行它们正在执行的操作所花费的时间相比,此后完成的处理花费了很长时间。
如果我错了,很高兴有人纠正我。 :)