设计模式系列(一)——单例模式

1. 什么是单例

单例模式是最常见,最容易掌握的设计模式之一。所谓“单例”指的是在内存中只存在该类的一个实例。类通过使用一个私有的构造函数生成并维护一个私有的实例对象,并通过对外暴露一个公有方法来获取该实例。


2. 单例的优缺点

运用单例可以在不需要同时存在多个实例的环境中减少实例对象不断被创建与销毁对于系统性能的消耗。当产生一个比较消耗资源的对象时,使用单例能够减少系统的开销。当有资源竞争存在的情况下,利用单例也能够防止对于资源的多重占用。
 但是单例也同样存在着致命的缺点:扩展困难。单例由于需要维护一个自身的实例对象,所以无法作为接口或抽象类存在。

3. 单例的实现

单例模式根据创建实例的时机不同可以分为饿汉和懒汉。顾名思义,饿汉就是在类装载时就迫不及待地生成实例对象了。相反,懒汉则是先不着急生成实例,等需要用到时再去生成。

3.1 饿汉们

饿汉所声明得静态实例对象能够使其在类加载时就已被创建好。在多线程的环境中,在内存中只会存在一个实例对象。
  1. /**
  2. * 使用静态变量的懒汉
  3. */
  4. public class Singleton {
  5. private Singleton (){}
  6. private static Singleton instance = new Singleton();
  7. public static Singleton getInstance() {
  8. return instance;
  9. }
  10. }
当然我们也可以通过静态代码块的形式达到同样的效果:
  1. /**
  2. * 使用静态方法块的饿汉
  3. */
  4. public class Singleton {
  5. private Singleton (){}
  6. private Singleton instance = null;
  7. static {
  8. instance = new Singleton();
  9. }
  10. public static Singleton getInstance() {
  11. return this.instance;
  12. }
  13. }

3.2 懒汉们

与饿汉不同,懒汉会等到我们需要取得实例时才会去生成。因此我们会很容易想到如下的方法:
  1. /**
  2. * 线程不安全的初级懒汉
  3. */
  4. public class Singleton {
  5. private Singleton (){}
  6. private static Singleton instance;
  7. public static Singleton getInstance() {
  8. if (instance == null) {
  9. instance = new Singleton();
  10. }
  11. return instance;
  12. }
  13. }
在单线程的环境中能够正常运行,不会产生出现多个实例的情况。但是在并发环境下,假设当A线程执行到第9行还没有获取到实例,若此时B线程此时正在执行第8行的判断操作,结果必然为真,A线程和B线程都会创建一个实例。为了保证线程安全需要对判断操作加锁:
  1. /**
  2. * 线程安全的懒汉
  3. */
  4. public class Singleton {
  5. private Singleton (){}
  6. private static Singleton instance;
  7. public static synchronized Singleton getInstance() {
  8. if (instance == null) {
  9. instance = new Singleton();
  10. }
  11. return instance;
  12. }
  13. }
在这段代码中对getInstance方法进行了加锁,这保证了多线程的安全。可是为了预防仅仅一次的初始化生成对象操作的线程安全竟然对整个方法加锁,这未免太浪费了。
  1. /**
  2. * 使用双重校验锁的懒汉
  3. */
  4. public class Singleton {
  5. private Singleton (){}
  6. private volatile static Singleton singleton;
  7. public static Singleton getSingleton() {
  8. if (singleton == null) {
  9. synchronized (Singleton.class) {
  10. if (singleton == null) {
  11. singleton = new Singleton();
  12. }
  13. }
  14. }
  15. return singleton;
  16. }
  17. }
使用双重校验锁来减小锁的粒度,在上锁前判断是否需要上锁,判断的开销比上锁的开销要小很多,因此使用双重校验锁的效率会比对方法加锁高。
  1. /**
  2. * 使用静态内部类的懒汉
  3. */
  4. public class Singleton {
  5. private Singleton (){}
  6. private static class SingletonHolder {
  7. private static final Singleton instance = new Singleton();
  8. }
  9. public static final Singleton getInstance() {
  10. return SingletonHolder.instance;
  11. }
  12. }
及时使用双重校验锁的效率比原先提高了不少,但是判断和加锁始终会对程序产生一定的开销。使用静态内部类能够使线程安全的懒汉无锁,其用到了类装载的机制来保障线程安全。只有调用getInstance方法时,才会装载内部类。

3.3 神奇的枚举

  1. /**
  2. * 使用枚举来实现单例
  3. */
  4. public enum Singleton {
  5. INSTANCE;
  6. private Singleton() {};
  7. public void MyMethod() {
  8. }
  9. }
这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,但是很少见到有人这么使用。

Netgear WNDR3800刷机指南

趁着过年前从X宝上入了二手的网件WNDR3800。洋垃圾的成色不敢恭维,不过好在能够正常使用。拿到手时路由器刷的是一个网友编译的比较老的openwrt固件r40431。

由于本人刚接触openwrt,网上的知识比较杂乱。经过一天的摸索,成功将openwrt r47805刷入。用的是最笨的办法,但是十分有效。
Tips:WNDR3800有两个版本。一个是普通版,另一个是定制的CH版。CH版刷机比较麻烦,我买的是普通版。

STEP 1:刷回原厂固件

这一步参考的是网件官方的教程,所以参考着别的型号的指南一步步走。很顺利就把路由器刷回原厂固件了。

STEP 2:刷openwrt固件

在原厂固件的基础上再刷上factory的固件包就可以了。我刷的是之前提到的网友编译的r47805的固件openwrt-haxc-r47805-2015-12-27-ar71xx-generic-wndr3800-squashfs-factory.img。进入路由器后台升级固件的页面,选择img文件上传。等待路由器重启之后就能拥有新的openwrt了。

网友编译的固件包里面集成了很多实用的小工具。免去了自己编译安装等繁琐的步骤,直接配置一下就能使用了。

VMware vSphere Hypervisor 6(ESXi)详细安装指南

放假在家,准备着手研究下openstack,无奈自己的笔记本内存小的可怜。刚好家里有台废弃的台式机,台式机能点亮,就是显卡会时不时地闹脾气。想想还是给它安个ESXi吧,这样显示方面的问题就不是问题了。可是在安装ESXi时遇到了一些麻烦,当然这些麻烦将会被逐个击破。
Tips:什么是VMware vSphere Hypervisor。
VMware vSphere Hypervisor是采用Linux内核的虚拟化专用操作系统,又称ESXi。
那接下来我们就一步步开始安装。

STEP 1:下载

进入官网,产品里面找到vSphere Hypervisor。
之后可能要注册登录,完了之后就能找到下载的地方了。
这里需要下载两个文件。一个是ESXi的镜像,用来安装到服务器上的。还有一个是客户端的安装包,是用来操控服务器的。

STEP 2:安装ESXi

最简单的步骤就是:
  1. 刻录ESXi镜像
  2. 在服务器中安装
整个安装过程没有什么难度。如果当中没有遇到什么错误或者警告,一切顺利的话那么恭喜你!然而我就没有这么幸运了。
  • 无法从u盘启动:平时经常用u盘制作的安装盘来替代光盘刻录。可是ultraISO制作的ESXi的安装盘并不能引导安装。这时可以使用UNetbootin来制作u盘镜像。
Tips:制作时u盘盘符不要选错了!!!制作过程中弹出是否覆盖menu.c32时选择否!!!
  • nfs41client failed to load
安装时遇到这个问题是没有网卡驱动引起的,所以我们可以使用ESXi-Customizer手动给镜像中加入驱动。我的网卡是螃蟹厂的,如果你的网卡是intel或是别的可以到找一找。
  • 虚拟化未开启
这个问题很好解决,现在的cpu都支持虚拟化,可以在bios中开启。

STEP 3:安装客户端

无脑安装,一路next

STEP 4:添加许可证

通过客户端连接至服务器

点击图中右上角的编辑按钮添加许可证。这时你可能会问,我的许可证在哪里取?那就回到刚刚的下载页面去找找吧。


好了安装工作顺利结束,如果有vmware或是virtualbox的使用经验的话,使用起来应该没有太大难度。