总结来源于《深入理解JVM虚拟机》
- 程序次序规则(Program Order Rule) :
在一个线程内
, 按照控制流顺序, 书写在前面的操作先行发生于书写在后面的操作; - 管程锁定规则(Monitor Lock Rule) : 一个unlock操作先行发生于后面对同一个锁的lock操作。 这里必须强调的是“
同一个锁
”, 而“后面”是指时间上的先后
; - volatile变量规则(Volatile Variable Rule) : 对一个
volatile变量
的写操作先行发生于后面对这个变量的读操作, 这里的“后面”同样是指时间上的先后
; - 线程启动规则(Thread Start Rule) : Thread对象的start()方法先行发生于
此线程的每一个动作
; - 线程终止规则(Thread Termination Rule) : 线程中的所有操作都先行发生于对此线程的终止检测, 我们可以通过
Thread::join()
方法是否结束、 Thread::isAlive()
的返回值等手段检测线程是否已经终止执行; - 线程中断规则(Thread Interruption Rule) : 对线程interrupt()方法的调用先行发生于被中断线程代码检测到中断事件的发生, 可以通过T
hread::interrupted()
方法检测到是否有中断发生; - 对象终结规则(Finalizer Rule) : 一个对象的初始化完成(构造函数执行结束) 先行发生于它的
finalize()
方法的开始; - 传递性(Transitivity) : 如果操作A先行发生于操作B, 操作B先行发生于操作C, 那就可以得出操作A先行发生于操作C的结论。
代码中包含join、yield、DaemonThread 故可能与八大原则有差异
public class MyTest {
public static void main(String[] args) {
// 設置一个钩子线程,在JVM退出时输出日志
Runtime.getRuntime().addShutdownHook(
new Thread(() -> System.out.println("JVM 退出成功!")));
/**
* 守护线程运行中,它的存在与否不会关系到JVM退出
* 换句话说就是:线程分用户线程和非用户线程(如守护线程),只要用户线程存活,那么JVM就不会退出
* 守护线程拥有自动结束自己生命周期的特性,而非守护线程不具备这个特点。jvm中的垃圾回收线程就是典型的守护线程,
*/
Thread daemonThread = new Thread(() -> {
System.out.println("守護綫程運行中");
try {
// 守护线程休眠10s
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
daemonThread.setDaemon(true);
daemonThread.start();
long startTime = System.currentTimeMillis();
A a = A.getInstance();
Thread t1 = new Thread(() -> {
// 线程让步,但是并不代表别的线程一定会在它之前获取CPU执行权,而且如果持有锁的话,是不会释放当前锁的,
// 与wait不同的是,wait会进入阻塞状态,并且会释放当前持有的锁。
Thread.yield();
a.method1();
System.out.println(Thread.currentThread().getName() + "线程执行完毕,此时 var = " + a.var);
}, "t1 ==> ");
t1.start();
Thread t2 = new Thread(() -> {
Thread innerThread = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(new Random().nextInt(3));
} catch (InterruptedException e) {
e.printStackTrace();
}
a.method3();
System.out.println(Thread.currentThread().getName() + "线程执行完毕,此时 var = " + a.var);
}, "innerThread ==> ");
innerThread.start();
try {
innerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 执行这个方法必须等达 innerThread 执行完毕,所以 var的值一定是method3()的值
a.method2();
System.out.println(Thread.currentThread().getName() + "线程执行完毕,此时 var = " + a.var);
}, "t2 ==> ");
t2.start();
// 此时存活的线程数为:gc、main以及自定义的守护线程
while (Thread.activeCount() != 3) {
Thread.yield();
}
// JVM退出的时候,实际线程执行的时间远远小于守护线程的存活时间
System.out.println("所有的任务执行完毕!执行时间 = " + (System.currentTimeMillis() - startTime));
}
}
class A {
public int var;
private static A a = new A();
private A() {
}
public static A getInstance() {
return a;
}
public synchronized void method1() {
var = 3;
}
public synchronized void method2() {
int b = var;
}
public void method3() {
//注意这里和method1 method2 用的可不是同一个锁哦
synchronized (new A()) {
var = 4;
}
}
}