内容简介:最近两天被极客时间的新课刷群刷屏。刷屏的标题大多是“学了这么多年 Java,却连 singleton 都不会用”、“面试总被问高并发,你真的会么”这一类标题党。内容千篇一律是推荐极客时间打新的课程,《Java 并发编程实战》。高并发哥又不是没做过,随手找了一下,发现陈皓在 2009 年的一篇文章就提到了正确的解法,以及背后的原因。《文中给出几种功能上正确的 singleton 写法。
最近两天被极客时间的新课刷群刷屏。刷屏的标题大多是“学了这么多年 Java,却连 singleton 都不会用”、“面试总被问高并发,你真的会么”这一类标题党。内容千篇一律是推荐极客时间打新的课程,《Java 并发编程实战》。
高并发哥又不是没做过,随手找了一下,发现陈皓在 2009 年的一篇文章就提到了正确的解法,以及背后的原因。《 深入浅出单实例 SINGLETON 设计模式 》。
文中给出几种功能上正确的 singleton 写法。
// version 1.4
public class Singleton {
private volatile static Singleton singleton = null;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton== null) {
singleton= new Singleton();
}
}
}
return singleton;
}
}
请留意私有变量的描述词 volatile
,目的是不让编译器对指令进行重 排序 优化。
// version 1.5
public class Singleton {
private volatile static Singleton singleton = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return singleton;
}
}
这是自动加载版本。每次加载类的时候,实例就生成了。所以加载类的过程可能会很慢(特别是有很多继承、引用的情况)。
// version 1.6
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
这是对上面 1.5 版本的修正。 SingletonHolder
是个私有类,并且在 Singleton
加载的时候才会被调用, INSTANCE
才会被真正创建。
这段代码是即确保了线程安全,又实现了懒加载的较优办法。
还有一个所谓最优(优雅?代码最少?)的办法,不过不建议大家使用,可读性实在不太高。有点奇技淫巧的意思,大大牺牲了代码的可读性。
public enum Singleton{
INSTANCE;
}
利用了 enum
的创建是线程安全这一特性。
PS:PHP 中没有 singleton 的困扰,因为 php 语言特点决定的。php-fpm 本身就是 accepter-worker 并发模式,程序员写的 PHP 程序其实只是 worker,worker 与 worker 之间由 fpm 完成资源隔离和协调,PHP 程序员并不需要从内存数据的层面考虑并发的情况。所以有句话讲得不错, singleton 在 PHP 语言中不是一个好实践(practice) 。PHP 的 singleton 用简单的工厂模式就够了。
今天抽空找了下 MQTT 的 QoS2 实现方式,记录如下。原科普文链接《 MQTT QoS 深度解读 》。
无论是 QoS2 还是 transaction,原理都是一样的: 通过一次代价非常小、成功概率足够高的操作,作为最后确认的依据 。这样做并不是说绝对不出错,而是出错的概率足够低,实践中可以忽略。
sequenceDiagram participant Publisher participant Broker participant Subscriber Publisher->>Publisher: Store(Msg) Publisher->>Broker: PUBLISH(QoS2, Msg) Broker->>Broker: Store(Msg) Broker->>Publisher: PUBREC Publisher->>Broker: PUBREL Broker->>Subscriber: PUBLISH(QoS2, Msg) Broker->>Publisher: PUBCOMP Publisher->>Publisher: Delete(Msg) Subscriber->>Subscriber: Store(Msg) Subscriber->>Broker: PUBREC Broker->>Subscriber: PUBREL Subscriber->>Subscriber: Notify(Msg) Subscriber->>Broker: PUBCOMP Broker->>Broker: Delete(Msg) Subscriber->>Subscriber: Delete(Msg)
简单一点的模型,如果不需要中间的 broker,则流程如下。
sequenceDiagram participant Publisher participant Subscriber Publisher->>Publisher: Store(Msg) Publisher->>Subscriber: (1) PUBLISH(QoS2, Msg) Subscriber->>Subscriber: Store(Msg) Subscriber->>Publisher: (2) PUBREC Publisher->>Subscriber: (3) PUBREL Subscriber->>Subscriber: Notify(Msg) Subscriber->>Publisher: (4) PUBCOMP Subscriber->>Subscriber: Delete(Msg) Publisher->>Publisher: Delete(Msg)
从简化以后的模型可以看到,publisher 和 subscriber 有两次交互。第一次,publisher 把 msg 推送给 subscriber,对应 PUBLISH
/ PUBREC
指令。第二次,publisher 等于是询问 subscriber,“你是不是收到一次”,对应 PUBREL
/ PUBCOMP
指令。
如果没有第 (3)/(4)步, PUBREL
/ PUBCOMP
指令,实际就是 QoS1, 至少收到一次
。
再少一点,如果没有 (2)/(3)/(4) 步,只剩第 (1) 步,实际就是 QoS0, 至多只发送一次 。
科普文里面提问,为什么 MQTT QoS2 是两次“握手”,而不是像 TCP 一样,三次握手。我觉得这个问题太教条了。为什么 negotiate 就一定要想到 TCP 呢?当然,如果一定要回答,最本质的区别就是,MQTT QoS2 通讯是单向的,而 TCP 连接的通讯是双向的。单向的只需要一方取信于另外一方即可,而双向通讯需要两方都取信于对方。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 用技术解决“非技术”问题
- 数据安全治理重要相关技术——脱敏技术
- 零信任技术进阶篇:关键技术及挑战
- 零信任技术进阶篇:关键技术及挑战
- 2021 技术展望 | 走向未来的实时生成技术
- 前端技术演进(一):Web前端技术基础
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Where Wizards Stay Up Late
Katie Hafner / Simon & Schuster / 1998-1-21 / USD 16.00
Twenty five years ago, it didn't exist. Today, twenty million people worldwide are surfing the Net. "Where Wizards Stay Up Late" is the exciting story of the pioneers responsible for creating the most......一起来看看 《Where Wizards Stay Up Late》 这本书的介绍吧!