我们在写程序的时候,大部分时候,会把类定义成为public类型的,那么任何类都可以随意的创建该类的对象。但是有时候,这种做法并没有任何意义,频繁的创建对象和回收对象造成内存损耗,所以就有了单例模式。
一个类只能创建一个对象,则这个类被成为单例类,这种模式被成为单例模式。
单例模式的原则是:
单例模式分为:懒汉模式、饿汉模式和等级模式
/**
* 懒汉模式,特征是待到使用时,才创建该类对象
*/
public class Single {
// 定义一个类变量,来存储该类对象
private static Single single;
// 隐藏构造器
private Single() {
}
// 定义一个方法供外部调用,返回一个该类唯一的对象
public static Single getSingle() {
if (single == null) {
single = new Single();
}
return single;
}
public static void main(String[] args) {
Single s1 = Single.getSingle();
Single s2 = Single.getSingle();
if (s1 == s2) {
System.out.println("Single类是单例模式");
} else {
System.out.println("Single类不是单例模式");
}
}
}
/**
* 饿汉模式 饿汉模式特征是在类加载时候已经创建好实例待调用,并且该实例不可变
*/
public class Single {
// 直接创建该类的实例,该实例不可变
private static final Single single = new Single();
// 隐藏构造函数
private Single() {
}
// 创建一个方法供外部调用,返回该类的实例
public static Single getSingle() {
return single;
}
public static void main(String[] args) {
Single s1 = Single.getSingle();
Single s2 = Single.getSingle();
if (s1 == s2) {
System.out.println("Single类是单例模式");
} else {
System.out.println("Single类不是单例模式");
}
}
}
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 单例模式之登记模式,特征是事先维护一组map存放一个实例,当创建实例时,先查看map是否存在,如果存在,则直接返回,如果不存在,则先存入,再返回
*/
public class Single {
// 定义一个map,用来登记实例
private static Map<String, Single> map = new HashMap<String, Single>();
// 先在map中存放一个Single实例
static {
Single single = new Single();
map.put(single.getClass().getName(), single);
}
// 隐藏构造器
private Single() {
}
// 定义一个方法供外部调用,用来返回实例,需要传入一个参数作为map中的“键”
public static Single getSingle(String key) {
// 如果传入的参数为null,则讲类名称赋值给它
if (key == null) {
key = Single.class.getName();
}
// 根据传入的“键”判断是否存在“值”,如果不存在,则将该
if (map.get(key) == null) {
try {
map.put(key, (Single) Class.forName(key).newInstance());
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return map.get(key);
}
public static void main(String[] args) {
Single single1 = Single.getSingle(null);
Single single2 = Single.getSingle(null);
System.out.println(single1 == single2);
}
}
饿汉式这种一开始就创建实例的方式,线程是安全的,懒汉式则不同,看代码
public class Single {
// 定义一个类变量,来存储该类对象
private static Single single;
// 隐藏构造器
private Single() {
}
// 定义一个方法供外部调用,返回一个该类唯一的对象
public static Single getSingle() {
if (single == null) { //当线程执行到这里挂起时,别的线程获取执行权限执行到这里,还会继续给single创建实例,这样就造成了线程安全问题。
single = new Single();
}
return single;
}
public static void main(String[] args) {
Single s1 = Single.getSingle();
Single s2 = Single.getSingle();
if (s1 == s2) {
System.out.println("Single类是单例模式");
} else {
System.out.println("Single类不是单例模式");
}
}
}
为了避免懒汉式的线程安全问题,我们需要给他加上代码同步
public class ThreadForSingle {
public static void main(String[] args) {
}
}
class Single {
private Single() {
}
private static Single single = null;
public static Single getSingle() {
synchronized (Single.class) {
if (single == null) {
single = new Single();
}
}
return single;
}
}
当线程进来判断出single为null时,遇到问题挂起,其余的线程则无法进来,这样就保证了线程的安全