HZNU_QYGK 2024-06-06 15:24 采纳率: 27.3%
浏览 10

java8 jvm安全点问题

java版本:8
代码如下

public class Test {
    public static int num = 0;
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable=()->{
            long beginTime = System.currentTimeMillis();
            for (int i = 0; i < 1000000000; i++) {
                for (int j = 0; j < 10; j++) {
                    num++;
                }
            }
            System.out.println("子线程执行结束,耗时:" + (System.currentTimeMillis() - beginTime));
        };

        new Thread(runnable).start();
        new Thread(runnable).start();
        long beginTime = System.currentTimeMillis();
        Thread.sleep(1000);
        System.out.println("主线程睡眠时间:" + (System.currentTimeMillis()-beginTime));
        System.out.println("num = " + num);
    }
}

运行上面代码时,运行打印如下:
子线程执行结束,耗时:3263
子线程执行结束,耗时:3265
主线程睡眠时间:3265
num = 1768648854

可以看到主线程睡眠时间应该是1000但是实际是3265,经过翻找答案可知是由于safepoint机制导致的,所以safepoint触发的机制是什么,上面的代码何时触发了safepoint,为什么将Thread.sleep的时间调整到500时,输出的结果就正常了,下面时正常的输出结果:
主线程睡眠时间:506
num = 1906054945
子线程执行结束,耗时:2764
子线程执行结束,耗时:2764

  • 写回答

1条回答 默认 最新

  • 阿里嘎多学长 2024-06-06 15:24
    关注

    以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:


    Java虚拟机(JVM)中的安全点(Safepoint)机制是JVM在执行过程中,为了确保在执行某些需要暂停线程的操作时,所有线程都处于一个安全的状态。这些操作可能包括垃圾回收、线程dump、线程挂起等。安全点机制确保在这些操作执行时,不会破坏JVM的状态。

    安全点机制的工作原理:

    1. 定义安全点:JVM在代码中定义一些特定的位置作为安全点,通常是在循环的末尾或者方法调用的入口处。
    2. 线程暂停:当JVM需要执行需要暂停线程的操作时,它会向所有线程发送信号,要求它们在达到下一个安全点时暂停。
    3. 响应信号:线程在执行过程中,会定期检查是否有来自JVM的暂停信号。如果收到信号,线程会在达到下一个安全点时暂停。
    4. 操作执行:一旦所有线程都暂停,JVM就可以安全地执行需要的操作。
    5. 线程恢复:操作完成后,JVM会通知所有线程恢复执行。

    在提供的Java代码示例中,何时触发了安全点?

    在代码中,Thread.sleep(1000)调用是一个可能触发安全点的操作,因为它需要确保在睡眠期间JVM可以安全地进行垃圾回收或其他需要暂停线程的操作。

    为什么当Thread.sleep的时间从1000毫秒调整到500毫秒时,输出结果变得正常?

    Thread.sleep()的时间减少时,JVM可能有更多的机会在不触发安全点的情况下执行其他操作,从而减少了线程暂停的时间,使得主线程的睡眠时间更接近预期的500毫秒。

    为什么主线程的睡眠时间比预期的1000毫秒要长,实际耗时为3265毫秒?

    这可能是因为在Thread.sleep()期间,JVM执行了安全点检查和可能的垃圾回收等操作,这些操作需要时间,因此实际的睡眠时间会超过预期的1000毫秒。

    为什么num变量的值与预期不符,实际值为1768648854?

    num变量的值是由两个子线程并发修改的结果。由于Java内存模型中的可见性和有序性问题,以及现代处理器的指令重排和缓存一致性问题,两个线程对num变量的修改可能不会立即对另一个线程可见,导致最终的值与预期不符。

    相关的代码实现:

    代码实现已经在问题描述中给出,即多线程环境下对共享变量num的并发修改。

    相关的参考资料:

    1. 深入理解Java虚拟机:JVM高级特性与最佳实践 - 周志明著,详细介绍了JVM的内部机制,包括安全点。
    2. Java并发编程实战 - Brian Goetz等著,讨论了Java内存模型和并发编程中的常见问题。

    请注意,上述解释是基于对JVM和并发编程的一般理解,具体的JVM实现和优化可能会有所不同。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 6月6日

悬赏问题

  • ¥15 如何构建全国统一的物流管理平台?
  • ¥100 ijkplayer使用AndroidStudio/CMake编译,如何支持 rtsp 直播流?
  • ¥20 和学习数据的传参方式,选择正确的传参方式有关
  • ¥15 这是网络安全里面的poem code
  • ¥15 用js遍历数据并对非空元素添加css样式
  • ¥15 使用autodl云训练,希望有直接运行的代码(关键词-数据集)
  • ¥50 python写segy数据出错
  • ¥20 关于线性结构的问题:希望能从头到尾完整地帮我改一下,困扰我很久了
  • ¥30 3D多模态医疗数据集-视觉问答
  • ¥20 设计一个二极管稳压值检测电路