互联网技术07——单例和多线程

单例模式实现方式:

  1. 懒汉模式
  2. 饿汉模式
  3. 静态内部类
  4. 双重检查

第一种,懒汉模式,顾名思义,就是什么时候需要,我什么时候创建,示例代码:

package com.company;

/**
 * Created by BaiTianShi on 2018/8/16.
 */
public class SingleModal {
    private static SingleModal sm;

    public static SingleModal getSingleModal(){
        if(null == sm){
            return new SingleModal();
        }
        return sm;
    }
    
}

但是这有线程安全问题,当多个线程访问时,会多次创建 singleModal对象。解决办法是给 getSSingleModal方法加上关键字。正因为如此,这种懒汉模式就会并发效率会特别低。

第二种,饿汉模式。饿汉模式思想就是空间换时间。只要类装载,就会创建出singleModal实例,不管会不会用到,这就造成了空间的浪费。有调用就返回创建的 sm实例,没有调用就一直放着。

package com.company;

/**
 * Created by BaiTianShi on 2018/8/16.
 */
public class SingleModal {
    private static SingleModal sm = new SingleModal();

    public static SingleModal getSingleModal(){
        return sm;
    }

}

第三种内部类方式

package com.company;

/**
 * Created by BaiTianShi on 2018/8/16.
 */
public class SingleModal {

    private static class innerSingleModal{
        private static SingleModal sm = new SingleModal();
    };

    public static SingleModal getSingleModal(){
        return innerSingleModal.sm;
    }

}

静态内部类在SingleModal初始化时是不会被加载的,只有调用getSingleModal方法时才加载内部类并实例化。实例化的同时,就将sm初始化了。当再被调用的时候,因为innerSingleModal已经初始化完毕了,不会重新初始化,因为innerSingleModal初始化的过程中sm也初始化完毕了,所以整个过程sm只实例化一次。并且完全没有加锁,支持高并发,还是线程安全的(静态内部类只在第一次调用时加载)

第四种双重检查:

package com.company;

/**
 * Created by BaiTianShi on 2018/8/16.
 */
public class SingleModal {
    private static SingleModal sm ;

    public static SingleModal getSingleModal(){
        if(null == sm){
            try {
                //模拟初始化前的准备工作
                Thread.sleep(2000);
                
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (SingleModal.class){
                if(null == sm){
                    return new SingleModal();
                }
            }
        }
        return sm;
    }

}

调用getSingleModal方法,如果SingleModal已经实例化好则直接返回,如果没实例化好,就要给类加锁后去创建SingleModal。之所以加锁,是因为要使其他线程阻塞,然后其他线程共同等待当前线程实例化一个sm。但是在上锁前,趁着第一个线程执行准备工作时,已经有多个线程过了第一个if判断了,假设有A、B、C三个线程都在执行初始化前的准备工作。当线程A第一个拿到锁后,B、C线程执行的synchronized处时就要等待。当A实例化好SingleModal后,B、C在分别进入synchronized后的代码。这时如果不判空,B、C将会再次分别创建SingleModal实例,所以这里一定要再判断一次是否为空。同时,在给类上锁之前,有多少个线程进入了第一个if,就要有多少个线程在synchronized前等待 ,也就是说双重检查机制仍然不能完全避免线程等待。所以总体来看,静态内部的方式是最理想的。不过有人说现在用枚举方式可实现单例模式,课程学习结束后会将此方法补上。

猜你喜欢

转载自blog.csdn.net/qq_28240551/article/details/81714594