6.单例模式

1.什么是单例模式?

确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例

这个其实很好理解,我们windows的任务管理器其实就是一个单例。

 

2.单例模式的三个要点

(1)某个类只能有一个实例

(2)它必须自行创建这个实例

(3)它必须自行向整个系统提供这个实例

 

3.单例模式结构

单例模式只包含一个类,即单例类

单例模式只包含一个单例角色,也就是Singleton。在内部创建唯一实例,并通过静态方法getInstance()让客户的使用它。为了防止外部对单例实例化,构造函数用private

(1)单例类

public class Singleton {
    private static Singleton instance = null;//静态私有成员变量

    //私有构造函数
    private Singleton(){

    }

    //静态共有工厂方法,返回唯一实例
    public static Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

(2)测试

public class Client {
    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();

        if(s1 == s2){
            System.out.println("两个对象是相同实例");
        }else{
            System.out.println("两个对象不是相同实例");
        }
    }
}

(3)测试结果

 

4.单例模式应用实例——保证负载均衡器的唯一性

(1)单例类

public class LoadBalancer {
    //私有静态成员变量,存储唯一实例
    private static LoadBalancer instance = null;

    //服务器集合
    private List serverList = null;

    //私有构造函数
    private LoadBalancer(){
        serverList = new ArrayList();
    }

    //公有静态成员方法,返回唯一实例
    public static LoadBalancer getLoadBalancer(){
        if(instance == null){
            instance = new LoadBalancer();
        }
        return instance;
    }

    //增加服务器
    public void addServer(String server){
        serverList.add(server);
    }

    //删除服务器
    public void removeServer(String server){
        serverList.remove(server);
    }

    //使用Random类随机获取服务器
    public String getServer(){
        Random random = new Random();
        int i = random.nextInt(serverList.size());
        return (String)serverList.get(i);
    }

}

(2)测试类

public class Client {
    public static void main(String[] args) {
        //创建4个LoadBalancer对象
        LoadBalancer balancer1,balancer2,balancer3,balancer4;
        balancer1 = LoadBalancer.getLoadBalancer();
        balancer2 = LoadBalancer.getLoadBalancer();
        balancer3 = LoadBalancer.getLoadBalancer();
        balancer4 = LoadBalancer.getLoadBalancer();

        //判断负载均衡器是否相同
        if(balancer1 == balancer2 &&balancer2 == balancer3 &&balancer3 == balancer4){
            System.out.println("负载均衡器具有唯一性");
        }

        //增加服务器
        balancer1.addServer("Server1");
        balancer1.addServer("Server2");
        balancer1.addServer("Server3");
        balancer1.addServer("Server4");

        //模拟客户端请求的分发
        for(int i = 0;i<20;i++){
            String server = balancer1.getServer();
            System.out.println("分发请求至服务器:"+server);
        }
    }
}

(3)输出结果

 

5.饿汉式单例与懒汉式单例

(1)饿汉式单例

在定义静态变量的时候实例化单例类

/**
 * 饿汉式单例
 */
public class EagerSingleton {
    private static EagerSingleton instance = new EagerSingleton();

    //私有构造函数
    private EagerSingleton(){

    }

    //静态共有工厂方法,返回唯一实例
    public static EagerSingleton getInstance(){
        return instance;
    }
}

 

(2)懒汉式单例与双重检查锁定

懒汉式单例被加载时不会自己实例化,而是在第一次调用getInstance()方法时实例化

但这里要注意,如果多线程同时调用getInstance()方法,可以使用关键字synchronized。但是用synchronized有一个不好的地方:每次调用getInstance()需要进行线程锁定判断,会降低系统性能。

因此采用双重检查锁定方法保证线程安全

/**
 * 懒汉式单例
 */
public class LazySingleton {
    //被volatile修饰的成员变量可以确保多个线程都能正确处理
    private volatile static LazySingleton instance = null;

    //私有构造函数
    private LazySingleton(){

    }

    public static LazySingleton getInstance(){
        //第一重判断
        if(instance == null){
            //锁定代码块
            synchronized (LazySingleton.class){
                //第二重判断,主要用于多线程同时进了这里,第一个创建了,第二个就不需要再创建了
                if(instance == null){
                    instance = new LazySingleton();//创建单例实例
                }
            }
        }
        return instance;
    }

}

 

(3)饿汉式和懒汉式的比较

饿汉式:

        优:

        (1)无需考虑多线程

        (2)调用速度反应时间均优于懒汉式

        缺:

        (1)资源利用效率低于懒汉式

        (2)加载时间较长

 

(4)使用静态内部类实现单例模式

在单例类中增加一个静态内部类,在该内部类中创建单例对象,再将该对象通过getInstance()方法返回外部使用。

注:该方法适用于java,很多其他面向对象语音不支持。因为依托java虚拟机保证线程安全性

/**
 * 该方法适用于java,很多其他面向对象语音不支持。因为依托java虚拟机保证线程安全性
 */
public class IODHSingleton {
    private IODHSingleton(){

    }

    //静态内部类
    private static class HolderClass{
        private final static IODHSingleton instance = new IODHSingleton();
    }

    public static IODHSingleton getInstance(){
        return HolderClass.instance;
    }

    public static void main(String[] args) {
        IODHSingleton s1,s2;
        s1 = IODHSingleton.getInstance();
        s2 = IODHSingleton.getInstance();
        System.out.println(s1 == s2);
    }
}

 

6.单例模式的优缺点

优:

(1)提供了唯一实例的受控访问

(2)节约系统资源

(3)允许可变数量的实例

缺:

(1)拓展困难

(2)单例类职责过重

(3)实例化对象长时间不被使用会被GC回收掉

 

7.使用场景

(1)系统只需要一个实例对象

(2)只允许一个公共访问点

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鹏哥哥啊Aaaa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值