学习目标:
1、了解单例模式的概念
2、编写单例模式
3、在项目中正确使用单例模式
学习过程:
一、什么是单例
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。
如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。要实现这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
二、单例的实现方式
单例类只能自己创建自己,所有我们把构造方法设置为私有,同时提供一个共有的静态方法提供一个而且只有一个实例,这样就可以完成单例了。实现代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /** * 单例模式 整个应用程序只能有一个实例 * * @author Administrator * */ public class Database { private static Database database = null ; // 1、构造方法修改为私有 private Database() { } public static Database newInstance() { if (database == null ) { database = new Database(); } return database; } } |
我们可以写一个Run方法测试一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class Run { public static Database database1 = null ; public static Database database2 = null ; public static void main(String[] args) { database1 = Database.newInstance(); database2 = Database.newInstance(); System.out.println(database1.toString()); System.out.println(database2.toString()); } } |
查看控制台的打印,可见database1和database2这两个对象是指向同一个内存空间的。
三、多线程下的单例实现
一般情况下,上面的代码已经可以实现单例模式,但是在多线程下就会有问题了,我们尝试修改上面的Run测试类,在多线程下情况如何,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | public class Run { public static Database database1 = null ; public static Database database2 = null ; public static void main(String[] args) { new Thread() { public void run() { database1 = Database.newInstance(); } }.start(); new Thread() { public void run() { database2 = Database.newInstance(); } }.start(); try { Thread.sleep( 500 ); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(database1.toString()); System.out.println(database2.toString()); } } |
多运行几次,就会发现两个对象有时候可能指向了不同空间,控制台如下:
这时候我们的修改原来的单例的实现类,把线程也要考虑进去,修改Database类如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | /** * 单例模式 整个应用程序只能有一个实例 * * @author Administrator * */ public class Database { private static Database database = null ; private static Object object = new Object(); // 1、构造方法修改为私有 private Database() { } public static Database newInstance() { // 保证 if (database == null ) { System.out.println( "如果两个线程同时进来了,必须排队" ); synchronized (object) { if (database == null ) { database = new Database(); } } } return database; } } |
这样就完成了多线程下的单例模式了。