- 饿汉模式
class Person{
//私有化构造器
private Person() {
}
private static Person instance = new Person();
public static Person getInstance() {
return instance;
}
}
- 懒汉模式
非安全模式下的懒汉模式
class Person{
private Person() {
}
private static Person instance = null;
public static Person getInstance() {
if (instance == null) {
instance = new Person();
}
return instance;
}
}
安全模式
class Person{
private Person() {
}
private static Person instance = null;
public synchronized static Person getInstance() {
if (instance == null) {
instance = new Person();
}
return instance;
}
}
该安全模式使用同步方法,已经解决了线程安全问题
但是synchronized的作用域太大,损耗性能-->尽量减小synchronized的作用域
解决方案:使用双重检查锁机制
双重检查锁:
可以使用"双重检查锁"的方式来实现,就可以即实现线程安全,又能够使性能不受太大影响,那什么是"双重检查锁"机制呢?
所谓"双重检查锁"机制,指的是:并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在再进行下面的同步块,这是第一重检查,进入同步后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查,这样一来,就只需要同步一次了,从而减少了多次在同步的情况下进行判断所浪费的时间.
"双重检查锁"机制的实现会使用关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。
注意:在java1.4及以前版本中,很多关键字对于volatile的实现问题,会导致"双重检查锁"的失败,因此"双重检查锁"机制只能用在java5及以上的版本.
提示:由于volatile关键字可能会屏蔽掉虚拟机中一些必要的代码优化,所以运行效率并不是很高,因此一般建议,没有特别的需要,不要使用,也就是说,虽然可以使用"双重检查锁"机制来实现线程安全的单例,但是并不建议大量采用,可以根据情况来选用
class Person{
private Person() {
}
private static Person instance = null;
public static Person getInstance() {
if (instance == null) {
synchronized(Person.class){
if (instance == null) {
instance = new Person();
}
}
}
return instance;
}
}