java设计模式之单例模式
程序员文章站
2023-01-14 09:30:19
单例模式属于java设计模式的一种,最常见实现方式有以下几种 懒汉、饿汉、双重检查单例、静态内部类单例。 单例模式的特点: 1:单例类只能有一个实例 2:单例类的唯一实例化必须由自己完成 3:单例类给其他对象提供唯一实例 ......
本文属于原创内容,如需转载请标明来源。
单例模式属于java设计模式的一种,最常见实现方式有以下几种 懒汉、饿汉、双重检查单例、静态内部类单例。
单例模式的特点:
1:单例类只能有一个实例
2:单例类的唯一实例化必须由自己完成
3:单例类给其他对象提供唯一实例
如何保证第一个和第三个特点呢->2个实例化的对象相等说明是同一实例化对象
1 public class singletontest { 2 3 public static void main(string[] args) { 4 singleton singleton1=singleton.getinstance(); 5 singleton singleton2=singleton.getinstance(); 6 /* 7 * 利用set的特性检验2个对象是同一个实例 8 * 输出1代表这两个变量代表的同一个实例对象 9 * 10 */ 11 set<singleton> set=new hashset<singleton>(); 12 set.add(singleton1); 13 set.add(singleton2); 14 system.out.println("set长度"+set.size()); 15 //set长度1 16 } 17 }
如何理解第二个特点:单例类是的实例化必须由自己完成->私有化构造器
private singleton() { }
1 package com.innerclass; 2 3 public class singletontest { 4 5 public static void main(string[] args) { 6 //我们在同包中创建一个其他类 并尝试创建singleton实例 得的一个错误 7 //the constructor singleton() is not visible 8 //构造方法singleton() 是不可见的 也就是说我们无法创建singleton的实例对象 9 singleton singleton=new singleton(); 10 11 } 12 }
- 饿汉式的实现(饿汉式也就是不管你用不用我都把实例化创建好放在这里,你需要用的时候就拿去用)
优点:始终只有一个singleton实例对象 所以线程安全
在类加载的同时已经创建好一个静态对象,调用时反应速度快
缺点:jvm加载类的时候一定会实例化,如果一直没调用getinstance()方法,会造成资源的浪费。
1 public class singleton { 2 private singleton() { 3 } 4 private static singleton singleton=new singleton(); 5 public static singleton getinstance() { 6 return singleton; 7 } 8 }
- 线程安全的懒汉式(何为懒汉也就是按需加载 只有在使用的时候才对单例类去初始化)
优点:按需加载,不会造成资源的浪费
缺点:无synchronized关键字的单例类会造成线程的不同步
1 private singleton() { 2 3 } 4 public static singleton singleton=null; 5 public synchronized singleton getinstance(){ 6 if(singleton==null) { 7 return new singleton(); 8 } 9 return singleton; 10 }
此处说一下为什么要给getinstance()方法加锁(实际意义上是给singleton.class类类型加锁,有兴趣可以去了解一下)
假设上面的代码中没有 synchronized 关键字
public class singleton { private singleton() { } private static singleton singleton=null; public static singleton getinstance(){ if(singleton==null) { try {
//假设线程阻塞情况 thread.sleep(100); return new singleton(); } catch (interruptedexception e) { // todo auto-generated catch block e.printstacktrace(); } } return singleton; } public static void main(string[] args) { set<singleton> singletons= new hashset<singleton>(); for (int i = 0; i < 10; i++) { singletons.add(singleton.getinstance()); } system.out.println(singletons.size());
//10
//说明多线程下懒汉式可能会创建多个实例对象
} }
这种情况下,线程安全可以保证,但是效率问题受到人的诟病了。因为线程第一次实例化类之后,往后每次获取实例化对象仍然需要去获取单例类的锁和释放锁。增加了性能的损耗。于是有了以下2中进阶方式的单例模式
-
双重检查单例(不同于上一个懒汉式实现方式 只有当对象未实例化的时候才选择去加锁创建唯一实例,若是对象已初始化直接返回已初始化对象,提高了效率)
1 public class singleton { 2 /** 3 * 双重检查单例 4 */ 5 private singleton() { 6 7 } 8 private static volatile singleton singleton; 9 public static singleton getinstance() { 10 if(singleton!=null) { 11 synchronized (singleton.class) { 12 if(singleton!=null) { 13 singleton=new singleton(); 14 } 15 } 16 } 17 return singleton; 18 } 19 }
volatile关键字 在这里不做叙述,有兴趣的可以直接去百度它的作用
- 静态内部类实现单例(利用原理是内部类的对外不可见性)
public class singleton { private singleton() { } private static class singletonhandler{ private static singleton singleton=new singleton(); } public singleton getinstance() { return singletonhandler.singleton; } }
推荐大家在多线程开发中使用双重检查单例和静态内部类单例,集成了懒汉和饿汉的优点。
如何只是单线程没有线程同步情况的话按照情况选择懒汉和饿汉式。
学习过程中,如有不对,请指出。
上一篇: 在丈母娘家吃饭
下一篇: 美国极客使用RFID猫咪喂食系统