在研究Java并发, 内存模型时, 遇到了一些问题?
public class VolatileDemo {
final static int MAX = 5;
static int initVal = 0;
static volatile int b=0;
public static void main(String[] args) {
new Thread(() -> {
int localVal = initVal;
while (localVal < MAX) {
if (initVal != localVal) {
b++;
System.out.printf("The iniVal is updated to [%d]\n", initVal);// A步骤
localVal = initVal;
}
}
}, "Reader").start();
new Thread(() -> {
int localVal = initVal;
while (localVal < MAX) {
System.out.printf("The initVal will be cahnged to [%d]\n", ++localVal);
initVal = localVal;
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Updater").start();
}
}
以上的代码中, A 步骤永远不会发生(我测试了很多次, 我知道如果给变量加了volatile之后可以解决这个问题)。为什么?
public class UnsafeThread implements Runnable {
private static int count = 0;
public void increase(){
count++;
}
public void run() {
for (int i = 0; i < 1000000000; i++) {
increase();
}
}
public static void main(String[] args) {
UnsafeThread myThread = new UnsafeThread();
Thread thread1 = new Thread(myThread);
Thread thread2 = new Thread(myThread);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
System.out.println(count);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
感谢你能阅读到这, 如果知道答案, 望解惑一二, 谢谢
你代码错了,第一个死循环了,好吧,下面代码逻辑有点小问题,就不改了哈
public class VolatileDemo {
final static int MAX = 5;
static int initVal = 0;
static volatile int b=0;
public static void main(String[] args) {
new Thread(() -> {
int localVal = initVal;
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (localVal < MAX) {
if (initVal != localVal) {
b++;
System.out.printf("The iniVal is updated to [%d]\n", initVal);// A步骤
localVal = initVal;
}
break;
}
}
}, "Reader").start();
new Thread(() -> {
int localVal = initVal;
while (localVal < MAX) {
System.out.printf("The initVal will be cahnged to [%d]\n", ++localVal);
initVal = localVal;
System.err.println("initVal:"+initVal);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Updater").start();
}
}
代码本身没问题, 是为了让第二个线程更改了值之后通知第一个线程的。。你给 initVal 加 volatile 试一下
public class VolatileDemo {
final static int MAX = 5;
static volatile int initVal = 0;
static volatile int b=0;
public static void main(String[] args) {
new Thread(() -> {
int localVal = initVal;
while (localVal < MAX) {
if (initVal != localVal) {
b++;
System.out.printf("The iniVal is updated to [%d]\n", initVal);// A步骤
localVal = initVal;
}
}
}, "Reader").start();
new Thread(() -> {
int localVal = initVal;
while (localVal < MAX) {
System.out.printf("The initVal will be cahnged to [%d]\n", ++localVal);
initVal = localVal;
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Updater").start();
}
}
输出结果
The initVal will be cahnged to [1]
The iniVal is updated to [1]
The initVal will be cahnged to [2]
The iniVal is updated to [2]
The initVal will be cahnged to [3]
The iniVal is updated to [3]
The initVal will be cahnged to [4]
The iniVal is updated to [4]
The initVal will be cahnged to [5]
The iniVal is updated to [5]
Process finished with exit code 0
@阿进的写字台: 不用volatile,加下面的sleep
new Thread(() -> {
int localVal = initVal;
while (localVal < MAX) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (initVal != localVal) {
b++;
System.out.printf("The iniVal is updated to [%d]\n", initVal);// A步骤
localVal = initVal;
}
}
}, "Reader").start();
@阿进的写字台: 我想是while 和if 一起用出的问题,中间时间不够
我觉得 这里 有三个线程 一个 main 一个 是第一个thread 还一个 就是下面一个thread 线程 他们会copy一份值到他们自己的栈中,然后 操作这些值,所以每次第一个 永远是没有进去(自己想的 ,可能不对)
是的, 不对
@阿进的写字台: 尴尬 就知道 volatile 是针对原子操作啥的 每个线程 有他们自己的loacl域
volatile:使用 volatile 关键字修饰的变量,在线程间可见。即一个线程修改了变量,另一个线程也会同步。