java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。
单例模式有以下特点:
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。选择单例模式就是为了避免不一致状态,避免政出多头。
在程序开发中,Service和Dao都可以设置为单例模式(保证线程安全)。
1. 饿汉单例模式
饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的。
public class StudentServiceImpl {
private static StudentServiceImpl studentService;
static{ //静态块
System.out.println("-----static 在类加载到JVM中会触发,且触发一次-----");
studentService = new StudentServiceImpl();
}
//为了控制创建对象的数量,将构造方法设为私有
private StudentServiceImpl(){}
//单例模式中,创建对象的方法一定是静态的
public static StudentServiceImpl getInstane(){
return studentService;
}
//主函数测试
public static void main(String[] args) {
System.out.println(StudentServiceImpl.getInstane());
System.out.println(StudentServiceImpl.getInstane());
}
}
测试结果:
-----懒汉模式测试-----
实例被创建
StudentServiceImpl@4c4975
StudentServiceImpl@4c49752. 懒汉单例模式
在第一次调用的时候实例化自己。public class StudentServiceImpl {
private static StudentServiceImpl studentService;
//为了控制创建对象的数量,将构造方法设为私有
private StudentServiceImpl(){
System.out.println("实例被创建");
}
//懒汉模式,在使用时才创建,
public static StudentServiceImpl getInstane(){
if(studentService == null){
studentService = new StudentServiceImpl();
}
return studentService;
}
//主函数测试
public static void main(String[] args) {
System.out.println("-----懒汉模式测试-----");
System.out.println(StudentServiceImpl.getInstane());
System.out.println(StudentServiceImpl.getInstane());
}
}
注意:此时的程序是线程不安全的。
public class StudentServiceImpl {
private static StudentServiceImpl studentService;
//为了控制创建对象的数量,将构造方法设为私有
private StudentServiceImpl(){
System.out.println("实例被创建");
}
//懒汉模式,在使用时才创建,synchronized: 同一事件只能有一个线程进入临界区
public static StudentServiceImpl getInstane(){
//if:为了提升性能
if(studentService == null){
synchronized (StudentServiceImpl.class) { //定制synchronized所属
//if:保证创建对象数量唯一
if(studentService == null){
studentService = new StudentServiceImpl();
}
}
}
return studentService;
}
//主函数测试
public static void main(String[] args) {
System.out.println("-----懒汉模式测试-----");
System.out.println(StudentServiceImpl.getInstane());
System.out.println(StudentServiceImpl.getInstane());
}
}
为了保证线程安全,可以采用以下代码:
3. 登记式单例
类似Spring里面的方法,将类名注册,下次从里面直接获取。
public class Dengjishi {
private static Map<String,Dengjishi> map = new HashMap<String,Dengjishi>();
static{
Dengjishi single = new Dengjishi();
map.put(single.getClass().getName(), single);
}
//保护的默认构造子
protected Dengjishi(){
System.out.println("-----实例对象被创建-----");
}
//静态工厂方法,返还此类惟一的实例
public static Dengjishi getInstance(String name) {
if(name == null) {
name = Dengjishi.class.getName();
System.out.println("name == null"+"--->name="+name);
}
if(map.get(name) == null) {
try {
map.put(name, (Dengjishi) Class.forName(name).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
return map.get(name);
}
public static void main(String[] args) {
System.out.println(Dengjishi.getInstance("Dengjishi"));
System.out.println(Dengjishi.getInstance("Dengjishi"));
}
}