单例:顾名思义,就是保证只有一个实例。
(以前一个类可以创建多个实例对象,而单例模式是说在一个类中只有一个实例对象)
实现单例模式的三步:
1)私有化构造方法 如:private Student(){}
详解:私有化构造方法之后,因为不能实例化私有构造方法,所以利用反射来创建实例。
首先根据反射获取构造方法,因为构造方法是私有的,所以设置构造方法的修饰符为public,在调用newInstance()方法创建实 例。这样每调用一次newInstance()方法,还是会新创建一个实例,这样创建的也不是单例的,结果创建实例还是多个。
2)定义一个静态的本类属性 如:private static Student s = new Student();
详解:static修饰的属性在内存中只会存在一份,在本类中创建一个实例,并将属性设置成私有的static修饰的属性在类加载后第一时间初始化,一旦初始化就会创建一个实例。
3)提供一个公共的静态方法,返回唯一实例
如:public static Student getInstance(){
return s;//返回实例
}
详解:在第二步中创建的实例是私有的,所以需要提供一个公共的静态方法供外界调用。因为是静态方法,所以通过类名.方法名就可直接调用。
这样多次调用获取的便是同一个唯一实例。
在类加载后第一时间就初始化Student对象,在没有调用创建实例方法之前,这个对象就已经创建了,所以又称为饿汉式单例模式。
下面介绍懒汉式单例模式:
懒汉式单例模式在类加载时不会创建实例,而在调用创建实例的方法时才创建(不需要就不创建,需要对象时再创建)
如:
private Student(){}
private static Student s;
public static Student getInstance(){
if(s == null){
s = new Student();
}
return s;
}
单例模式分为饿汉式和懒汉式,饿汉式线程安全,懒汉式线程不安全。
在懒汉式单例模式中创建实例的方法中加入synchronized关键字可以使线程安全,加了synchronized关键字也就意味着一个线程进入该方法后,必须执行完真个方法后下一个线程才可以进入该方法执行。
但是这样会把整个方法锁住,锁的代码太多,锁的粒度太大。
解决办法:使用双重锁(双重判定锁) 这样只会锁住几行代码,提升了性能
如:public static Student getInstance(){
if(s == null){
synchronized(Student.class){
if(s == null){
s = new Student();
}
}
}
return s;
}