JVM在初始化阶段(即在)Class在加载和使用线程之前),将执行类别的初始化。在初始化期间,JVM会得到一个锁。该锁可以同步多线程对同一类的初始化。
虚拟机会保证一个类的虚拟机会clinit()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行clinit()方法完成。若在一类clinit()方法中长时间的操作可能会导致多个过程堵塞(需要注意的是,虽然其他线程会被堵塞,但如果执行clinit()方法后,其他线程唤醒后不会再进入clinit()方法。在同一个加载器下,一种类型只初始化一次。
基于这一特点,可以采用这种方法实现线程安全延迟初始化方案,
锁定双重检查
public class SingleInstanceTest {
private SingleInstanceTest() { }
//volatile关键字 public static volatile SingleInstanceTest singleInstanceTest;
public static SingleInstanceTest getInstance() {
//第一次检查 if (singleInstanceTest == null) { synchronized (SingleInstanceTest.class) { ///第二次检查 if (singleInstanceTest == null) {
//分配内存空间 memory = allocate() ///初始化对象 ctorInstance(memory) //将singleInstanceTest指向刚刚分配的内存地址 singleInstanceTest = new SingleInstanceTest(); } } } return singleInstanceTest; } } 这种方法有几点需要注意:
- 1.第一次判空的目的:如果第一次检查instance不为null,因此,无需执行以下加锁和初始操作,因此可以大大降低synchronized性能费用
- 2.第二次空缺的目的:想象一下这种情况。线程1和2同时判断第一次空缺,锁定位置堵塞。如果没有第二次空缺,线程1执行后线程2将再次执行,初始化两次。两次空缺后,DCL更安全,一般没有问题。但当并发量特别大时,仍然会有风险。也就是说,volatile改发起作用。
- 3.volatile的作用:
singleInstanceTest = new SingleInstanceTest();
该代码可分解为
最后
我希望你能有一个好的态度,想进入什么样的公司想清楚,不一定是一家大公司,我选择的不是一家大工厂。当然,如果你不知道选择者没有计划,那就选大公司吧!我希望我们能选择我们想去的公司,然后投资或推动,而不是有一家公司想让我去!还有就是不要害怕,也不要有压力,用平常心对待,但要做好充分的准备。最后,我希望每个人都能得到满意 offer !如果目前有工作,请珍惜努力,找工作其实挺累很辛苦的。
以上是京东、小米、腾讯、头条、阿里巴巴、美团等公司19年来与上述面试题相关的几十套字节跳动。将技术点整理成视频和PDF(其实比预期多花了很多精力) 诸多细节。
由于篇幅有限,这里以图片的形式向大家展示一小部分。GitHub免费获取
md)
[外链图片转存中…(img-aS0mMHOz-1644051945658)]