JVM:浅谈静态代码块和<clinit>方法

概念

静态内部类形式的单例可保证线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。

理论依据是<clinit>方法:<clinit>()方法是编译器给某些类(带有静态代码块,或者静态变量、静态内部类)自动生成的方法,目的是,确保静态语句块有序顺序的执行,并且只会执行一次。

下面是取材于《深入理解JVM虚拟机》第7章-7.3.5节的内容:

虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。

如果在一个类的<clinit>()方法中有耗时很长的操作,就可能造成多个进程阻塞(需要注意的是,其他线程虽然会被阻塞,但如果执行<clinit>()方法后,其他线程唤醒之后不会再次进入<clinit>()方法。同一个加载器下,一个类型只会初始化一次。),在实际应用中,这种阻塞往往是很隐蔽的。

测试demo

package com.bryant.singleton;


public class TestClinitMethod {


    // 静态代码块,有且只会被JVM编译执行一次
    static {
        if (true) {
            System.out.println(Thread.currentThread() + "init TestClinitMethod, check out whether static code block can be executed several times...");
        }
    }


    public static void main(String[] args) {
        Runnable runnable = new Runnable(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread() + " start...");
                TestClinitMethod testClinitMethod = new TestClinitMethod();
                System.out.println(Thread.currentThread() + " end...");
            }
        };


        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);


        thread1.start();
        thread2.start();
    }
}

日志打印:

Thread[main,5,main]init TestClinitMethod, check out whether static code block can be executed several times...
Thread[Thread-0,5,main] start...
Thread[Thread-0,5,main] end...
Thread[Thread-1,5,main] start...
Thread[Thread-1,5,main] end...

验证理论:

  • static {}静态代码块有且只被执行一次

  • 即使多线程下,同个类被new一次,虚拟机会保证一个类的<clinit>()方法会被正确加锁、同步的执行一次

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值