1.什么是安全点
安全点是一种特殊的执行位置,在这些位置,JVM可以安全地停止线程来进行全局性的操作,比如垃圾回收。在这些点上,程序的状态是已知的并且稳定的,这意味着JVM可以暂停所有线程而不用担心破坏程序的一致性
2.那些可以作为安全点
1.方法调用完成后
2.循环体末尾
3.异常处理后
4.其他任何会导致程序状态变更后的地方
3.代码演示
public static void foo() {
System.out.println("foo方法开始执行====");
long start = System.currentTimeMillis();
for (int i = 0; i < 0x77777777; i++) {
sum += Math.sqrt(i);
}
System.out.println("foo - >"+(System.currentTimeMillis()-start));
}
public static void bar() {
System.out.println("bar方法开始执行====");
long start = System.currentTimeMillis();
for (int i = 0; i < 50_000_000; i++) {
new Object().hashCode();
}
System.out.println("bar - >"+(System.currentTimeMillis()-start));
}
public static void main(String[] args) {
//分别单独执行
new Thread(SafepointTest::foo).start();
new Thread(SafepointTest::bar).start();
}
博主电脑单独执行 foo,跑完输出 foo - >2840
bar - >2660
如果同时跑
foo - >2863
bar - >5518
可以发现 bar 方法从开始到结束所花费时间提供了近两倍。这是由于 bar() 不停的创建 new Object()对象,并调用hashCode方法,将会触发GC回收,而GC线程进行回收时,需要等待 其他线程都进入安全点(foo 线程循环结束),因此 bar() 方法执行时间大大增加。
4. UseCountedLoopSafepoints
可以添加 -XX:+UseCountedLoopSafepoints JVM参数进行优化
当启用 -XX:+UseCountedLoopSafepoints 选项时,JVM 会在循环中插入安全点,但这些安全点是基于循环迭代次数的计数器来确定的。这意味着,循环中的每个迭代不一定都会成为一个安全点,而是每隔一定次数的迭代才会插入一个安全点