java单例设计模式

单例设计模式是在软件系统中采用一定的方法,保证某个类只能存在一个实例对象,并且该类只能有一个静态方法来获取该对象。

注意下面各类实现方式中的测试代码都一样:需要注意导入的包路径即可。

package com.yefengyu;

import com.yefengyu.type2.Singleton;


public class Client
{
    public static void main(String[] args)
    {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1 == singleton2);
    }
}

1、实现方式一


该方式是静态常量实现的饿汉式类加载的时候便创建了实例):

package com.yefengyu.type1;

public class Singleton
{
    //类内部实例化
    private final static Singleton INSTANCE = new Singleton();

    //构造器私有化,防止new对象
    private Singleton()
    {
    }

    //对外提供公有方法调用
    public static Singleton getInstance()
    {
        return INSTANCE;
    }
}

1、类加载的时候实例化,防止多线程问题。

2、没有使用懒加载,类加载就产生对象,如果始终未使用则造成内存浪费。但是该对象只有一个,浪费空间也不是很大,可以使用,编写的时候非常简单。

2、实现方式二

该方式是静态代码块实现的饿汉式

package com.yefengyu.type2;

public class Singleton
{
    private final static Singleton INSTANCE;

    static
    {
        //使用静态代码块生成对象
        INSTANCE = new Singleton();
    }

    //构造器私有化,防止new对象
    private Singleton()
    {
    }

    //对外提供公有方法调用
    public static Singleton getInstance()
    {
        return INSTANCE;
    }
}

该方式和方式一的优缺点类似。

3、实现方式三


该方式是同步方法实现懒汉式只有第一次使用的时候才创建实例

package com.yefengyu.type3;

public class Singleton
{
    private static Singleton instance;

    //构造器私有化,防止new对象
    private Singleton()
    {
    }

    //只有在第一次使用的时候构造实例对象,使用synchronized避免多线程问题
    public static synchronized Singleton getInstance()
    {
        if (instance == null)
        {
            instance = new Singleton();
        }
        return instance;
    }
}

1、解决了线程不安全问题

2、效率低下,每次调用该方法都要涉及锁的操作。

3、不推荐使用。

问:java设计模式的单例模式,在懒汉式中一开始声明的类的实例化对象为什么只用private static声明,但没有加final关键字?而在饿汉式中声明实例是使用了private static final修饰?

答:如果是final非static成员,必须在构造器、代码块、或者直接定义赋值;如果是final static成员变量,必须直接赋值或者在静态代码块中赋值。而在懒汉式中如果直接赋值就达不到延迟加载的效果。

4、实现方式四


该方式是同步代码块实现懒汉式。

package com.yefengyu.type4;

public class Singleton
{
    private static Singleton instance;

    //构造器私有化,防止new对象
    private Singleton()
    {
    }

    //只有在第一次使用的时候构造实例对象,使用synchronized代码块和双重判断避免多线程问题,并且提供效率
    public static Singleton getInstance()
    {
        if (instance == null)
        {
            synchronized (Singleton.class)
            {
                if (instance == null)
                {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

1、解决了线程不安全问题

2、效率高,只有前面的少数线程可能会获取锁,只要实例被创建,后面的线程一般只需第一个if判断就返回了对象。

3、推荐使用。

5、实现方式五


该方式是静态内部类实现懒汉式。

package com.yefengyu.type5;

public class Singleton
{
    private static Singleton instance;

    //构造器私有化,防止new对象
    private Singleton()
    {
    }

    //静态内部类,在外部类加载的时候不会加载静态内部类
    private static class SingletonInstance
    {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance()
    {
        //只有在使用到静态内部类的时候才会加载,并且通过类加载机制保证在初始化的时候只有一个实例产生
        return SingletonInstance.INSTANCE;
    }
}

1、线程安全,使用类加载机制保证初始化时只有一个线程。

2、外部类装载的时候静态内部类不会装载,只有使用的时候才会装载,因此达成了懒汉式的效果。


单例设计模式的使用场景?

一个对象即可完成所有的工作,无需大量创建对象消耗资源。比如一个长连接,建立起来就可以不断发送数据,此时如果每来一个请求就建立一个连接,那么资源会消耗殆尽。

多线程测试:针对懒汉式

测试代码:

for (int i = 0; i < 1000; i++)
{
    new Thread(() -> {
        Singleton.getInstance();
    }).start();
}

在new实例的时候加上打印,如:

public static synchronized Singleton getInstance()
{
    if (instance == null)
    {
        System.out.println("创建实例");
        instance = new Singleton();
    }
    return instance;
}
这个时候可以去掉synchronized关键字,或者加上,查看打印效果,是打印一句还是多句。
posted @ 2019-07-14 08:51  代码梦工厂  阅读(1785)  评论(0编辑  收藏  举报