并发(五)-单例模式

这里系统的说一下单例模式。

本文参考的文章,地址如下:

微信公众号: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.主函数是静态的。

就说这么多了。。。

原文地址:https://www.cnblogs.com/lihao007/p/7739836.html