缓冲行对齐,这个应该是一个需要掌握的知识点,属于关于程序优化的奇技淫巧。
偶现于面试环节。
对齐的目的是为了解决伪共享(False Sharing)的发生。
不知道伪共享的朋友,建议去了解一下。
PPT 中的例子的源码来源是:
com.google.code.yanf4j.util.LinkedTransferQueue.PaddedAtomicReference
需要注意的是,在 Java8 里面,提供了更加优雅的解决方案:@Contented 注解。
这个也是一个非常经典的、关于单例模式的演变过程。
PPT 上一共四个单例模式的写法,我们一个个的看。
这就是我们耳熟能详的饿汉式单例。通过提前初始化的方式,解决了并发问题,保证了单例性。
这里面最关键的就是 final static 关键字。
作者也用了蓝色做以区分,肯定是有深意的。
来,一起背一遍类的加载过程:
加载、验证、准备、解析、初始化。
比如下面这个例子:
public static int value =123
变量 value,只有 static 修饰,那么该变量在准备阶段被赋上初始值,即 0。
在初始化阶段被赋上 123。
但是当再多一个 final 修饰的时候:
public final static int value =123
value 变量在准备阶段就会被赋上 123。
所以,你想想上面的饿汉式,是不是一个道理?
而这一方面的知识点,在《深入理解Java虚拟机》一书里面,写的还是很清楚的。
但是饿汉式有一个明显的劣势,那就是不管应用程序是否使用,都会被初始化出来。
这样并不优雅。
于是,就到了第二段程序,饱汉式。
在需要使用的时候,才进行初始化操作。
但是怎么保证线程安全呢?
通过在方法上加 synchronized 关键字的方式来保证了线程安全?
但是这个玩意真的安全吗?
这可能是面试官最喜欢问的问题之一吧。
要是你之前不知道,也许打死你也想不到还有拿到一个只初始化了一半的对象的情况。
简单来说就是 new Singleton()
不是原子性的,所以会导致 if 条件满足时,instance 并没有完全初始化。
于是就引出了下面这段程序:
传说中的双重检查加锁。
而这段程序最容易被“忽视”的就是 volatile 关键字了。
如果没有 volatile 关键字,那么这个程序也是废的。
还有,需要注意的是梁飞在这里备注了一个 jdk1.5+
。
为什么呢?
其实答案就写在《Java并发编程实战》的第 287 页:
在这本书里面,形容双重检查加锁的成语是:声名狼藉。
而且在图片里面可以看到:促使该模式出现的驱动力已经不复存在,并不是一种高效的优化措施。
现在,我觉得双重检查加锁主要还是应用在面试环节。
明明就不是一种高效的优化措施,却还是一个高频考点,为什么呢?
还不是八股文害人啊。
接下来说最后一种,也是作者推崇的方式:
这个骚操作的学名叫做“基于类初始化的单例模式解决方案”。
JVM 在 Class 被加载后,且被线程使用之前,也就是类的初始化阶段,会去获取一个锁。
这个锁可以保证多个线程对同一个类进行初始化时,只有一个线程能初始化成功。
而该方法的原理在《Java并发编程的艺术》一书的 3.8.4 章节解释的非常清楚。
什么?这两本书你都没有?
赶紧去搞一本吧,写的还是挺好的,我以前多次推荐过。
额......
这页我也没看明白。
我觉得肯定是有一个上下文的,只是梁飞没有写在 PPT 里面。
导致我看的云里雾里的。
这里只写到了 CountDownLatch 和 CyclicBarrier 。
其实还有一个很重要的、很常用的、工具类:Semaphore。
如果不知道,可以看看这篇文章:
如果你上面三个都不知道。
赶!紧!去!学!
打印出来,贴在电脑旁边,朗读并背诵本页。
最后说一句
文中提到的两个 PPT 和一个文件:
- 阿里巴巴(B2B)的服务框架探索.ppt
- Java并发编程常识.ppt
- hsdis-amd64.dll
关注公众号【why技术】,然后在后台回复关键字【ppt】即可获得。
才疏学浅,难免会有纰漏,如果你发现了错误的地方,可以在后台提出来,我对其加以修改。 感谢您的阅读,我坚持原创,十分欢迎并感谢您的关注。
我是 why,一个主要写代码,经常写文章,偶尔拍视频的程序猿。