什么是java中的惰性初始化_Java 惰性初始化

publicclass Lazy {

privatestaticbooleaninitial = false;

static {

Thread t = new Thread(new Runnable() {

publicvoid run() {

System.out.println("befor...");//此句会输出

/*

* 由于使用Lazy.initial静态成员,又因为Lazy还未初

* 始化完成,所以该线程会在这里等待主线程初始化完成

*/

initial = true;

System.out.println("after...");//此句不会输出

}

});

t.start();

try {

t.join();// 主线程等待t线程结束

} catch (InterruptedException e) {

e.printStackTrace();

}

}

publicstaticvoid main(String[] args) {

System.out.println(initial);

}

}

看看上面变态的程序,一个静态变量的初始化由静态块里的线程来初始化,最后的结果怎样?

当一个线程访问一个类的某个成员的时候,它会去检查这个类是否已经被初始化,在这一过程中会有以下四种情况:

1、这个类尚未被初始化

2、这个类正在被当前线程初始化:这是对初始化的递归请求,会直接忽略掉(另,请参考《构造器中静态常量的引用问题》一节)

3、这个类正在被其他线程而不是当前线程初始化:需等待其他线程初始化完成再使用类的Class对象,而不会两个线程都会去初始化一遍(如果这样,那不类会初始化两遍,这显示不合理)

4、这个类已经被初始化

当主线程调用Lazy.main,它会检查Lazy类是否已经被初始化。此时它并没有被初始化(情况1),所以主线程会记录下当前正在进行的初始化,并开始对这个类进行初始化。这个过程是:主线程会将initial的值设为false,然后在静态块中创建并启动一个初始化initial的线程t,该线程的run方法会将initial设为true,然后主线程会等待t线程执行完毕,此时,问题就来了。

由于t线程将Lazy.initial设为true之前,它也会去检查Lazy类是否已经被初始化。这时,这个类正在被另外一个线程(mian线程)进行初始化(情况3)。在这种情况下,当前线程,也就是t线程,会等待Class对象直到初始化完成,可惜的是,那个正在进行初始化工作的main线程,也正在等待t线程的运行结束。因为这两个线程现在正相互等待,形成了死锁。

修正这个程序的方法就是让主线程在等待线程前就完成初始化操作:

publicclass Lazy {

privatestaticbooleaninitial = false;

static Thread t = new Thread(new Runnable() {

publicvoid run() {

initial = true;

}

});

static {

t.start();

}

publicstaticvoid main(String[] args) {

// 让Lazy类初始化完成后再调用join方法

try {

t.join();// 主线程等待t线程结束

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(initial);

}

}

虽然修正了该程序挂起问题,但如果还有另一线程要访问Lazy的initial时,则还是很有可能不等initial最后赋值就被使用了。

总之,在类的初始化期间等待某个线程很可能会造成死锁,要让类初始化的动作序列尽可能地简单。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值