JDK设计模式应用——单例模式(Singleton)
《JDK源码分析》的分支,讲解设计模式在jdk中使用。
我们从三个方面讲述,一是:jdk源码中的设计模式;二是:讲解设计模式(UML图);三是:实现我们自己的设计模式代码。今天带来最简单的设计模式——单例模式(Singleton)。
一、jdk源码中的设计模式
我们先看java.lang包下的class Runtime
- public class Runtime {
- private Runtime() {}//私有的构造方法
- //Runtime类的私有静态实例
- private static Runtime currentRuntime = new Runtime();
- //获得静态实例的唯一方法
- public static Runtime getRuntime() {
- return currentRuntime;
- }
- }
解释:
(1)存在私有的构造函数,不能通过new来得到类的实例。
(2)私有的静态实例,一个class只能对应唯一的对象。
(3)只能通过:类.get方法获得这个唯一的对象实例。
我们可以通过如下代码验证:
- Runtime r1 = Runtime.getRuntime();
- Runtime r2 = Runtime.getRuntime();
- //“==”为地址判断,为true表示:r1与r2指向同一对象。
- System.out.println(r1 == r2);
结果显然为:true。
二、讲解设计模式(UML图)
上面是Singleton的UML图。
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。(来源——百度百科)
单例模式的思想使用在很多方面,比如:一台计算机可以有若干打印机,但是一个时间只能有一个Printer Spooler,避免两个文件同时输入到打印机中。
单例模式满足三个条件:
(1)某个类只能有一个实例。
(2)类必须自行创建这个类的实例(创建静态成员变量或者在类的静态方法中生成实例)。
(3)类必须自行向整个系统提供这个实例。
三、实现我们自己的设计模式
我们实现单例模式分为两种:1、静态成员变量 2、静态方法(有人成为饿汉式和懒汉式)
1、静态成员变量
- public class SingletonTest
- {
- //在类里面实例化静态成员变量
- private static SingletonTest singletonTest = new SingletonTest();
- private SingletonTest()
- {
- }
- public static SingletonTest getInstance()
- {
- return singletonTest;
- }
- }
2、静态方法(最常用的方法)
- public class SingletonTest
- {
- private static SingletonTest singletonTest = null;
- private SingletonTest()
- {
- }
- public static SingletonTest getInstance()
- {
- //在类的静态方法中实例化单例
- if (null == singletonTest)
- {
- singletonTest = new SingletonTest();
- }
- return singletonTest;
- }
- }
3、第二种方法构建单例模式是最常用的,但是在并发程序中会导致单例模式失效。
如下面的代码所示:
- public class SingletonTest
- {
- private static SingletonTest singletonTest = null;
- private SingletonTest()
- {
- }
- public static SingletonTest getInstance()
- {
- if (null == singletonTest)
- {
- try
- {
- Thread.sleep((long) (Math.random() * 4000));
- } catch (InterruptedException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- singletonTest = new SingletonTest();
- }
- return singletonTest;
- }
- public static void main(String[] args)
- {
- // 打印出两个对象
- new ThreadTest().start();
- new ThreadTest().start();
- }
- }
- class ThreadTest extends Thread
- {
- @Override
- public void run()
- {
- System.out.println(SingletonTest.getInstance());
- }
- }
输出的结果是:不是同一个对象,单例模式失效了。
- com.shy.test.SingletonTest@55fe910c
- com.shy.test.SingletonTest@3be4d6ef
对于单例模式(Singleton)来说,如果在 getInstance()方法中生成 Singleton 实例则可能会产生同步问题,即可能会生成两个不同的对象。
解释:
当两个线程同时执行到getInstance()方法时,此时singletonTest为null,两个线程都会分别实例化出一个对象,因此出现了两个对象。
解决方法:(使用synchronized解决同步问题)
- public class SingletonTest
- {
- private static SingletonTest singletonTest = null;
- private SingletonTest()
- {
- }
- public static SingletonTest getInstance()
- {
- if (null == singletonTest)
- {
- synchronized (SingletonTest.class)
- {
- singletonTest = new SingletonTest();
- }
- }
- return singletonTest;
- }
- }
总结:Java中单例模式(Singleton Pattern)定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”