Java中什么是易失性的,何时/如何使用它们? 公共类Volatile{ 挥发性int x=0; 公共静态void main(字符串a[]{ Volatile y=新Volatile(); 试验t1=新试验(y); 试验t2=新试验(y); t1.设定名称(“A”); t2.设定名称(“B”); t1.start(); t2.start(); } } 类测试扩展了线程{ 挥发性v; 测试(挥发性v){ 这个,v=v; } @凌驾 公开募捐{ 对于(int i=0;i
输出Java中什么是易失性的,何时/如何使用它们? 公共类Volatile{ 挥发性int x=0; 公共静态void main(字符串a[]{ Volatile y=新Volatile(); 试验t1=新试验(y); 试验t2=新试验(y); t1.设定名称(“A”); t2.设定名称(“B”); t1.start(); t2.start(); } } 类测试扩展了线程{ 挥发性v; 测试(挥发性v){ 这个,v=v; } @凌驾 公开募捐{ 对于(int i=0;i,java,multithreading,volatile,Java,Multithreading,Volatile,输出 public class Volatile { volatile int x = 0; public static void main(String a[]) { Volatile y = new Volatile(); test t1 = new test(y); test t2 = new test(y); t1.setName("A"); t2.setName("B");
public class Volatile {
volatile int x = 0;
public static void main(String a[]) {
Volatile y = new Volatile();
test t1 = new test(y);
test t2 = new test(y);
t1.setName("A");
t2.setName("B");
t1.start();
t2.start();
}
}
class test extends Thread {
Volatile v;
test(Volatile v) {
this.v = v;
}
@Override
public void run() {
for (int i = 0; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + "Says Before " + v.x);
v.x++;
System.out.println(Thread.currentThread().getName() + "Says After " + v.x);
}
}
}
最早在0之前
B在0之前到达
下午2点以后
B在2点之前睡觉
3点后休息
在1之后尽快标记变量volatile将阻止JVM缓存该值,但它不会为您解决同步问题(例如在修改变量和打印变量之间交换线程)
例如,线程A在0之前输出,然后被调出,以便线程B运行。该值仍然为零,因为A尚未更新它。然后B更新它,然后A返回并更新它,然后打印它。这意味着您可能最终会遇到以下情况:
ASays Before 0
BSays Before 0
BSays After 2
BSays Before 2
BSays After 3
ASays After 1 <--- Is it a cache value ?
BSays Before 3
ASays Before 3
BSays After 4
BSays Before 5
BSays After 6
ASays After 5 <--- Is it a cache value ?
ASays Before 6
ASays After 7
ASays Before 7
ASays After 8
ASays Before 0
BSays Before 0
ASays After 2
这不太理想
此外,println
本身不是原子的,因此它可能会在中途中断,导致线程持有过时的打印值(即,稍后在输出流中显示的理想值)
要正确更新和打印,应在需要原子化使用变量的块周围使用synchronized
,例如:
ASays Before 0
BSays Before 0
BSays After 2
BSays Before 2
BSays After 3
ASays After 1 <--- Is it a cache value ?
BSays Before 3
ASays Before 3
BSays After 4
BSays Before 5
BSays After 6
ASays After 5 <--- Is it a cache value ?
ASays Before 6
ASays After 7
ASays Before 7
ASays After 8
ASays Before 0
BSays Before 0
ASays After 2
但是,在您的特定情况下,您不能使用this
,因为它是thread对象,这意味着其中有两个对象,因此它们不会根据需要相互阻塞
您可以通过在thread类中引入一个静态对象来解决这个问题:
synchronized (this) {
System.out.println(Thread.currentThread().getName() + " before " + v.x);
v.x++;
System.out.println(Thread.currentThread().getName() + " after " + v.x);
}
并将其用于同步:
static Object o = new Object();
你看过吗?@MadProgrammer它说对一个可变变量的更改对其他线程总是可见的,这是真的,但问题仍然是这些更改实际上是什么时候提交的…@MadProgrammer你的意思是,我们永远不会确定增量是否完成。我说得对吗?如果是,那么我们永远无法预测多线程环境中的可变值。对吗?链接的答案对此有一些有趣的观点,因此您可以同时使用同步
和volatile
,或者使用原子
API,它为您提供了一些其他选项请纠正我,那么我为什么要使用volatile?如果我将同步,那么我可以使用简单的非易失性变量。这将产生同样的结果。我说的对吗?另外,我做了更改,正如你所说的,我仍然看到相同的值模式。@jWeaversynchronized
将保护数据不被修改,但如果数据被缓存,就不会了,因为易失性会阻止值被缓存,并让你实时访问,这是一种平衡行为。最近,我使用了Atomc
类而不是volatile类,我倾向于选择同步操作,因为有很多情况下volatile没有帮助。举个例子,当您想要一个一致的print modify print值时,这是不好的。事实上,我似乎还记得,基于变量的旧值修改变量是不合适的,因为Java不能保证x++
始终是原子的。@jWeaver对此表示歉意,事实证明在您的例子中,这个是两个不同的线程对象之一,因此它们不会同步。修改了答案来解决这个问题。