经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
23种设计模式之单例模式
来源:cnblogs  作者:锻心  时间:2019/7/29 9:11:25  对本文有异议

单例模式

单例模式分八种方式

1)饿汉式(静态常量)
2)饿汉式(静态代码块)
3)懒汉式(线程不安全)
4)懒汉式(线程安全,同步方法)
5)懒汉式(线程安全,同步代码块)
6)双重检查
7)静态内部类
8)枚举

饿汉式(静态常量)

  1. public class SingletonTest01 {
  2. public static void main(String[] args) {
  3.  
  4. // 测试
  5. Singleton s1 = Singleton.getInstance();
  6. Singleton s2 = Singleton.getInstance();
  7.  
  8. System.out.println(s1 == s2); // true
  9. }
  10. }
  11.  
  12. /**
  13. * 饿汉式(静态变量)
  14. * */
  15. class Singleton {
  16.  
  17. /**
  18. * 构造函数私有化,外部不能new
  19. * @param []
  20. * @date 2019/7/28 9:50
  21. **/
  22. private Singleton() {
  23.  
  24. }
  25.  
  26. /**
  27. * 本类内部创建实例对象
  28. * */
  29. private final static Singleton instance = new Singleton();
  30.  
  31. /**
  32. * 对外提供接口获取对象
  33. * @param []
  34. * @date 2019/7/28 9:51
  35. * @return Singleton
  36. **/
  37. public static Singleton getInstance() {
  38. return instance;
  39. }
  40.  
  41. }

  优缺点说明:
1)优点:这种写法比较简单,就是在类加载的时候就完成实例化。避免了线程同步问题。
2)缺点:在类加载的时候就完成实例化,没有达到Lazy Loading(懒加载)的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。
3)结论:这种方式可用可能造成内存浪费。

饿汉式(静态代码块)

  1. public class SingletonTest02 {
  2. public static void main(String[] args) {
  3. // 测试
  4. Singleton singleton1 = Singleton.getInstance();
  5. Singleton singleton2 = Singleton.getInstance();
  6.  
  7. System.out.println(singleton1 == singleton2); // true
  8. }
  9. }
  10.  
  11. /**
  12. * 饿汉式(静态代码块)
  13. * */
  14. class Singleton {
  15.  
  16. /**
  17. * 构造函数私有化,外部不能new
  18. * @param []
  19. * @date 2019/7/28 9:50
  20. **/
  21. private Singleton() {
  22.  
  23. }
  24.  
  25. /**
  26. * 本类内部创建实例对象
  27. * */
  28. private static Singleton instance;
  29.  
  30. /**
  31. * 在静态代码块中实例化对象
  32. * */
  33. static {
  34. instance = new Singleton();
  35. }
  36.  
  37. /**
  38. * 对外提供接口获取对象
  39. * @param []
  40. * @date 2019/7/28 9:51
  41. * @return Singleton
  42. **/
  43. public static Singleton getInstance() {
  44. return instance;
  45. }
  46. }

  优缺点:
1)这种方式和上面的方式类似的,优缺点一致。
2)结论:这种方式可用,但可能会造成内存浪费。

懒汉式(线程不安全)

  1. public class SingletonTest03 {
  2. public static void main(String[] args) {
  3. // 测试
  4. Singleton singleton1 = Singleton.getInstance();
  5. Singleton singleton2 = Singleton.getInstance();
  6.  
  7. System.out.println(singleton1 == singleton2); // true
  8. }
  9. }
  10.  
  11. /**
  12. * 懒汉式(线程不安全)
  13. * */
  14. class Singleton {
  15.  
  16. /**
  17. * 创建未初始化的对象
  18. * */
  19. private static Singleton instance;
  20.  
  21. /**
  22. * 构造函数私有化
  23. * */
  24. private Singleton() {
  25.  
  26. }
  27.  
  28. /**
  29. * 对外提供接口并实例化对象
  30. * 当使用该方法时,才实例化对象
  31. * */
  32. public static Singleton getInstance() {
  33. if (instance == null) {
  34. instance = new Singleton();
  35. }
  36. return instance;
  37. }
  38.  
  39. }

  优缺点:
1)起到了Lazy Loading的效果,但是只能在单线程的环境下使用。
2)如果在多线程下,一个线程进入if(singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了判断语句,这是就会造成多实例现象。
3)结论:在实际开发中,不可使用。

懒汉式(同步方法,线程安全)

  1. public class SingletonTest04 {
  2. public static void main(String[] args) {
  3. // 测试
  4. Singleton s1 = Singleton.getInstance();
  5. Singleton s2 = Singleton.getInstance();
  6.  
  7. System.out.println(s1 == s2);
  8. }
  9. }
  10.  
  11. /**
  12. * 懒汉式(同步方法,线程安全)
  13. * */
  14. class Singleton {
  15.  
  16. /**
  17. * 创建未实例化对象
  18. * */
  19. private static Singleton instance;
  20.  
  21. /**
  22. * 构造函数私有化
  23. * */
  24. private Singleton(){}
  25.  
  26. /**
  27. * 在同步锁下,进行判断实例化对象
  28. * @param []
  29. * @date 2019/7/28 10:33
  30. * @return Singleton
  31. **/
  32. public static synchronized Singleton getInstance() {
  33. if (instance == null) {
  34. instance = new Singleton();
  35. }
  36.  
  37. return instance;
  38. }
  39.  
  40. }

  优缺点:
1)解决了线程不安全问题。
2)效率太低,每个线程在想获取实例时,执行getInstance()方法都要进行同步。而其实这个方法只要执行一次就行,后面想获取该类实例,直接return就行了。
3)结论:在实际开发中,不可用。

懒汉式(同步代码块,线程不安全)

  1. public class SingletonTest05 {
  2. public static void main(String[] args) {
  3. // 测试
  4. Singleton s1 = Singleton.getInstance();
  5. Singleton s2 = Singleton.getInstance();
  6.  
  7. System.out.println(s1 == s2);
  8. }
  9. }
  10.  
  11. /**
  12. * 懒汉式(同步代码块,线程不安全)
  13. * */
  14. class Singleton {
  15.  
  16. private static Singleton instance;
  17.  
  18. private Singleton() {}
  19.  
  20. public static Singleton getInstance() {
  21. if (instance == null) {
  22. synchronized(Singleton.class) {
  23. instance = new Singleton();
  24. }
  25. }
  26.  
  27. return instance;
  28. }
  29. }

  优缺点:
1)这种方式本意是为了解决第四种方式效率低的问题。
2)但是这种同步并不能起到线程同步的作用,和第三种方式遇到的情况类似。
3)结论:在实际开发中,不可使用。

双重检验

  1. public class SingletonTest06 {
  2. public static void main(String[] args) {
  3. // 校验
  4. Singleton s1 = Singleton.getInstance();
  5. Singleton s2 = Singleton.getInstance();
  6.  
  7. System.out.println(s1 == s2); // true
  8. }
  9. }
  10.  
  11. /**
  12. * 双重校验
  13. * */
  14. class Singleton {
  15.  
  16. /** 创建未实例化对象 */
  17. private static volatile Singleton instance;
  18.  
  19. /** 构造函数私有化 */
  20. private Singleton() {}
  21.  
  22. /**
  23. * 进行双重校验,解决线程安全问题,同时解决懒加载问题,并且解决了效率问题
  24. * @param []
  25. * @date 2019/7/28 10:55
  26. * @return Singleton
  27. **/
  28. public static Singleton getInstance() {
  29. if (instance == null) {
  30. synchronized (Singleton.class) {
  31. if (instance == null) {
  32. instance = new Singleton();
  33. }
  34. }
  35. }
  36.  
  37. return instance;
  38. }
  39. }

  优缺点:
1)Double-Check概念是多线程开发中经常使用的方式,如代码中所示,通过两重if(instance == null)检查,保证了线程安全。
2)这样,实例化代码只要执行一次,后面再次访问就直接返回实例化对象,避免了重复的进行方法同步。
3)线程安全,延迟加载,效率较高。
4)结论:在实际开发中,推荐使用。

静态内部类

  1. public class SingletonTest07 {
  2. public static void main(String[] args) {
  3. // 测试
  4. Singleton s1 = Singleton.getInstance();
  5. Singleton s2 = Singleton.getInstance();
  6.  
  7. System.out.println(s1 == s2); // true
  8. }
  9. }
  10.  
  11. /**
  12. * 静态内部类
  13. * */
  14. class Singleton {
  15.  
  16. /**
  17. * 构造函数私有化
  18. * */
  19. private Singleton() {}
  20.  
  21. /**
  22. * 静态内部类,该类中实例化Singleton属性
  23. * */
  24. private static class SingletonInstance {
  25. private final static Singleton INSTANCE = new Singleton();
  26. }
  27.  
  28. /**
  29. * 对外提供接口获取实例化对象
  30. * */
  31. public static Singleton getInstance() {
  32. return SingletonInstance.INSTANCE;
  33. }
  34.  
  35. }

  优缺点:
1)这种方式利用类装载机制保证了在初始化实例时只有一个线程。
2)静态内部类方式在Singleton类被装载时不会立即实例化,而是在需要实例化时,调用getInstance()方法,才会装载SingletonInstance类,从而完成了Singleton的实例化。
3)类的静态属性只会在第一次加载类时初始化,所以在这里,JVM帮助我们保证了线程安全。
4)优点:避免了线程不安全,利用静态内部类特点实现了延迟加载,并且效率较高。
5)结论:在实际开发中,推荐使用。

枚举

  1. public class SingletonTest08 {
  2. public static void main(String[] args) {
  3. Singleton s1 = Singleton.INSTANCE;
  4. Singleton s2 = Singleton.INSTANCE;
  5.  
  6. System.out.println(s1 == s2); // true
  7. s1.sayOk();
  8. }
  9. }
  10.  
  11. /**
  12. * 枚举
  13. * */
  14. enum Singleton {
  15. /**
  16. * 属性
  17. * */
  18. INSTANCE;
  19. public void sayOk() {
  20. System.out.println("ok");
  21. }
  22. }

  优缺点:
1)通过枚举方式实现的单例模式。不仅可以避免多线程问题,而且还能防止反序列化重新创建对象。
2)这种方式也是Effective Java作者提倡的方式。
3)结论:推荐使用。

注意事项和细节说明

1)单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些频繁创建销毁对象,使用单例模式可以提高系统性能。
2)单例模式使用场景:需要频繁的进行创建和销毁对象、创建对象时耗时过多或耗费资源过多(即重量级对象),但又经常使用的、工具类对象、频繁访问数据库或文件的对象(数据源、session工厂)。

总结:在使用单例模式时,考虑的问题无非就是线程是否安全、是否延迟加载、效率是否高等问题。当线程安全、延迟加载、效率较高时,该方式的单例模式就可用。

原文链接:http://www.cnblogs.com/dx520/p/11259010.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号