单例模式

                            单例模式

为什么要使用单例?

保证一个类在内存中的对象唯一性,减少对象在初始化过程中消耗大量的内存,导致性能降低。

  1. 饿汉式 

public class SingletonDemo1 {

        private SingletonDemo1(){}

        private static SingletonDemo1 s = new SingletonDemo1();

        public static SingletonDemo1 getInstance(){return s;

        }

}

- 优点:没有加锁,执行效率会提高,线程安全(每次使用都会实例化对象)。

- 缺点:类加载时就初始化,浪费内存。

2.懒汉式 (线程不安全:创建和使用时,多线程之间互换)

 public class SingletonDemo2 {

        private SingletonDemo2(){}

        private static SingletonDemo2 s = null;

        public static SingletonDemo2 getInstance(){

                if(s == null){

                        s=new SingletonDemo2();

                }

                return s;

        }

}

- 优点:第一次调用才初始化,避免内存浪费。

- 缺点:必须加锁synchronized 才能保证单例,但加锁会影响效率。 

懒汉式使用双重加锁(JMM的指令重排(多核cpu):加上volatile--但用反射可破坏单例):

public class SingletonDemo2_1 {

        private SingletonDemo2_1() {}

        private static volatile SingletonDemo2_1 s = null;

        public static SingletonDemo2_1 getInstance() {

                if (s == null) {

                        synchronized (SingletonDemo2_1.class) {

                                if (s == null) {

                                        s = new SingletonDemo2_1();

                                }

                        }

                }

                return s;

        }

}

(3)枚举单例(推荐:反射不能破解)

public enum  SingletonDemo3 {

        INSTNCE;

        private InnerClass  _instance;

        private SingletonDemo3(){

                _instance = new InnerClass();  }

        public InnerClass getInstance(){

                return  _instance;}

        private static class InnerClass{}

}

(4)登记式模式(反射可破坏单例)

每使用一次,都往一个固定的容器中去注册并且将使用过的对象进行缓存,下次去取对象的时候,就直接从缓存中取值,以保证每次获取的对象都是同一个对象

public class SingletonDemo4 {

        private static Map<String, SingletonDemo4> map = new HashMap<String, SingletonDemo4>();

        static {

                SingletonDemo4 singleton = new SingletonDemo4();

                map.put(singleton.getClass().getName(), singleton);

        }

        private SingletonDemo4() { }

        //静态工厂方法 返回此类唯一的实例

        public static SingletonDemo4 getInstance(String name) {

                if (name == null) {

                        name = SingletonDemo4.class.getName(); }

                if (map.get(name) == null) {

                        try {

                                map.put(name, (SingletonDemo4) Class.forName(name).newInstance());

                        } catch (InstantiationException e) {

                                e.printStackTrace();

                        } catch (IllegalAccessException e) {

                                e.printStackTrace();

                        } catch (ClassNotFoundException e) {

                                e.printStackTrace();

                        }

                }

                return map.get(name);

        }

}

5 序列化和反序列划保证单例:重写readResolve; 

序列化就是说把内存中的状态通过转换成字节码的形式,从而转换一个IO流,写入到其他地方(可以是磁盘、网络IO),内存中状态给永久保存下来了

反序列化将已经持久化的字节码内容,转换为IO流,通过IO流的读取,进而将读取的内容转换为Java对象,在转换过程中会重新创建对象new

public class SingletonDemo6 implements Serializable{

        public  final static SingletonDemo6 INSTANCE = new SingletonDemo6();

        private SingletonDemo6(){}

        public static  SingletonDemo6 getInstance(){

                return INSTANCE;

        }

        private  Object readResolve(){

                return  INSTANCE;

        }

}

测试能否用反射破坏单例(只有枚举单例不能进行反射):

public class TestReflection {

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        System.out.println(SingletonDemo6.getInstance().hashCode());

        System.out.println("-----");

        Class<?> c1 = SingletonDemo6.class;

        Constructor<?> constructor = c1.getDeclaredConstructor();

        constructor.setAccessible(true);

        Object o = constructor.newInstance();

        System.out.println(o.hashCode());

    }

}

测试所用时间:

public class TestMultiThread {

    public static void main(String[] args) {

     final Set<Object> instanceSet = Collections.synchronizedSet(new HashSet<>());

     int count = 1000;

        CountDownLatch latch = new CountDownLatch(count);

        long start = System.currentTimeMillis();

        for (int i = 0; i < count; i++) {

            new Thread(new Runnable() {

                @Override

                public void run() {

// instanceSet.add(SingletonDemo1.getInstance()); //饿汉式消耗内存,用时:1260

// instanceSet.add(SingletonDemo2.getInstance()); //懒汉式线程不安全,用时:1185

//                  instanceSet.add(SingletonDemo2_1.getInstance());//懒汉式双重锁反射会破坏,用时:1291

//                  instanceSet.add(SingletonDemo3.INSTNCE.getInstance());//枚举单例(推荐)用时:2235

//                  instanceSet.add(SingletonDemo4.getInstance(null));//登记模式(推荐)用时:1367

testSingletonDemo6(); //序列化和反序列划保证单例 用时3618:

                  latch.countDown();

                }

            }).start();

        }

        try {

            latch.await();

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        long end = System.currentTimeMillis();

        System.out.println("===" +(end-start));

        System.out.println(instanceSet.size());

    }

    public  static  void   testSingletonDemo6(){

        SingletonDemo6 s1 = null;

        SingletonDemo6 s2 = SingletonDemo6.getInstance();

        FileOutputStream fos = null;

        try {

            fos = new FileOutputStream("Seriable.obj");

            ObjectOutputStream oos = new ObjectOutputStream(fos);

            oos.writeObject(s2);

            oos.flush();

            oos.close();

            FileInputStream fis = new FileInputStream("Seriable.obj");

            ObjectInputStream ois = new ObjectInputStream(fis);

            s1 = (SingletonDemo6)ois.readObject();

            ois.close();

            System.out.println(s1);

            System.out.println(s2);

            System.out.println(s1 == s2);

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

    }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值