单例(Singleton)模式
单例模式:为了确保一个类有且仅有一个实例,并未它提供一个全局访问点
单例和线程设计一个单例,需要确定何时实例化该类的单例对象,最简单的方式为:创建类的实例,并作为改类的静态成员变量,如下:
/** *Test类,SingleTon单例类 */ public class Test(){ private static SingleTon st = new SingleTon(); public static SingleTon getSingleTon(){ return st; } }
public class Main { public static void main(String[] args){ Test t1 = new Test(); Test t2 = new Test(); System.out.println(t1.getSingleTon().toString()); System.out.println(t2.getSingleTon().toString()); } }
输出结果为:
com.lubi.dp.singleton.SingleTon@770848b9
基本实现了单例的功能。如果不希望提前就创建单例实例,可以在第一次实例化的时候做个判断,判断是否已经实例化过,如:com.lubi.dp.singleton.SingleTon@770848b9
单例模式建议使用一个公共的静态方法去访问单例对象。如果该方法创建一个对象,需保证只有一个实例可以被创建。public static SingleTon getSingleTon(){ if(st == null) st = new SingleTon(); return st; }
在多线程环境中,上述代码无法避免多个线程同时初始化单例对象。假设第一个线程发现该单例对象为null,与此同时,第二个线程也在运行,发现该单例为null,此时两个线程将都会对改单例对象进行初始化。
#因此,需要使用锁进制避免不同线程间的执行问题
在java多线程开发中,常用的单例模式则为每个对象提供一个对象锁,使用synchronized关键字进行同步锁
package com.lubi.dp.singleton; public class Tool { private static Tool tool; private static Object classLock = Tool.class; private int sum; public Tool(){ synchronized(classLock){ sum = 0; } } public static Tool getTool(){ synchronized(classLock){ if(tool == null) tool = new Tool(); return tool; } } public void recordSum(){ sum++; System.out.print(sum+" "); } }
public class Main { public static void main(String[] args){ Tool tool = Tool.getTool(); for(int i=0;i<5;i++){ tool.recordSum(); } System.out.println(); Tool tool2 = Tool.getTool(); for(int i=0;i<5;i++){ tool2.recordSum(); } } }
Summary
单例模式保证了类仅有一个实例,并为其提供了一个全局的访问点。在多线程环境下必须使用同步锁机制管理协调不同的线程运行。