并发(五)-单例模式
这里系统的说一下单例模式。
本文参考的文章,地址如下:
微信公众号:Java后端技术
文章:Java多线程编程-(12)-单例模式几种写法的错与对
作者:徐刘根
主要是四大类:饿汉、懒汉、双重校验锁DCL、
1.饿汉模式
示例如下:
1 public class Singleton { 2 3 /*为了防止外部访问,所以实例是private的 4 为了在static方法中访问,所以必须是static 5 至于为什么,叫饿汉模式。我想,因为在程序走到下面这一行时, 6 会初始化,调用构造方法。在没有调用getInstance方法时,就创建好了实例。 7 因为,可能叫做饿汉模式吧*/ 8 private static Singleton singleton = new Singleton(); 9 10 private Singleton() { 11 System.out.println("666"); 12 } 13 public static Singleton getInstance() { 14 return singleton; 15 } 16 }
2.懒汉模式
示例如下:
1 public class SingletonByLazy { 2 3 private static SingletonByLazy singleton; 4 5 /*这里必须是private修饰符,否则,就可以new多个对象,这是单例模式最基本的保证*/ 6 private SingletonByLazy() {} 7 8 /*需要注意的是,必须加上synchronized关键字。否则会导致对象的访问变得不安全。 9 * 饿汉的优点是延迟加载,在你需要的时候进行加载。缺点是必须使用同步*/ 10 public static synchronized SingletonByLazy getInstance() { 11 if (singleton == null) { 12 singleton = new SingletonByLazy(); 13 } 14 return singleton; 15 } 16 }
3.双重校验锁DCL
代码比上面两种多一些,绕一些,但是思想还是值得学习的嘛!看下面的例子:
1 public class SingletonByDCL { 2 3 /*这里切记,volatile关键字不可以缺少。 4 * 不然会因为指令重排,导致在第一个判空时,将未初始化的对象返回。*/ 5 private volatile static SingletonByDCL singleton; 6 7 /*这里必须是private修饰符,否则,就可以new多个对象,这是单例模式SingletonByLazy.java最基本的保证*/ 8 private SingletonByDCL() {} 9 10 /*需要注意的是,必须加上synchronized关键字。否则会导致对象的访问变得不安全。 11 * 饿汉的优点是延迟加载,在你需要的时候进行加载。缺点是必须使用同步*/ 12 public static SingletonByDCL getInstance() { 13 if (singleton == null) { 14 synchronized (SingletonByDCL.class) { 15 if (singleton == null) { 16 singleton = new SingletonByDCL(); 17 } 18 } 19 } 20 return singleton; 21 } 22 }
4.静态内部类
1 public class SingletonByStaticClass { 2 3 /*通过类加载机制,保证创建单一对象*/ 4 private static class SingletonHolder { 5 private static final SingletonByStaticClass single = new SingletonByStaticClass(); 6 } 7 8 private SingletonByStaticClass() {} 9 10 /*对于JAVA的加载机制来说,当第一次访问类的静态字段时,会触发类的加载*/ 11 public static SingletonByStaticClass getInstance() { 12 return SingletonHolder.single; 13 } 14 }
接下来,我要单独说一下static关键字。因为非常重要。
小例子:
1 public class Test { 2 3 public void method01(){ 4 System.out.println("method01"); 5 } 6 7 public static void method02(){ 8 System.out.println("method02"); 9 } 10 11 public static void main(String args[]){ 12 new Test().method01(); 13 method02(); 14 } 15 } 16 17 18 执行结果: 19 method01 20 method02
例子很简单,但是要说明的地方是:静态方法中不能直接调用非静态方法。
为什么呢?首先static的成员是在类加载的时候初始化的,而非static的成员是在创建对象的时候初始化的。先后顺序是,先加载才能初始化。那么加载的时候,初始化static成员,非static成员是在创建对象的时候初始化的。也就是说,static属于类,而非static属于对象。
下面说static的特点:
1.随着类的加载而加载,随着类的消失而消失(能消失吗? 这里我有疑问,有待验证)。
2.静态先存在,对象后存在。
3.被所有对象共享。
4.直接调用
使用时注意事项:
1.静态方法只能方法静态成员。
2.静态方法中不能使用super this 关键字。原因呢,上方的解释,懂了的话,这一点自然就明白了。
3.主函数是静态的。
就说这么多了。。。
努力到无能为力,奋斗到感动上天!