演示代码
package concurrent;
public class JvmResortTest1 {
private static int x, y, a, b = 0;
private static int i = 0;
public static void main(String[] args) throws InterruptedException {
while (true) {
reSort();
}
}
private static void reSort() throws InterruptedException {
Thread thread1 = new Thread(() -> {
waitTime(1000);
a = 1;
x = b;
});
Thread thread2 = new Thread(() -> {
b = 1;
y = a;
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
i++;
if (x == 0 && y == 0){
System.out.println("第" + i + "次,(" + x + "," + y + ")");
}
x = 0;
y = 0;
a = 0;
b = 0;
}
public static void waitTime(int time){
long start = System.nanoTime();
long end;
do {
end = System.nanoTime();
}while (start + time >= end);
}
}
有输出:
第643407次,(0,0)
join方法分析
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
从源码中看出,首先join() 是一个synchronized方法, 里面调用了wait(),这个过程的目的是让持有这个同步锁的线程进入等待,因为主线程调用了thread1.join()方法,相当于在threadA.join()代码这块写了一个同步代码块,是主线程调用了所以主线程被阻塞了。然后在子线程thread1执行完毕之后,JVM会调用lock.notify_all(thread);唤醒持有thread这个对象锁的主线程,然后主线程会继续执行。
在本题中thead1和thead2都执行了start()方法,这两个线程的优先级是一样的,即使主线程拿到Thead1的锁 ,也不影响Thread2的执行。
(0,0)的产生的可能:指令重排序
从结果发现,存在(0,0)这种情况。因为,在实际运行时,代码指令可能并不是严格按照代码语句顺序执行的。当然这一结果并不是一定是指令重排造成的 ,内存可见性问题也可能造成这一结果。
指令重排序:Java语言规范规定JVM线程内部维持as-if-serial语义(不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变),程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以和代码顺序不一致。
线程1和线程2是两个完全独立的线程,根据as-if-serial语义来讲,在线程1中执行a=1,x=b;与线程2的操作是无关的。
(0,0)的产生的可能:内存可见性
由于不是volatile可能线程1更改a后,线程2没及时感知到。