java中单例的实现方式
1.饿汉式:饿汉式顾名思义,就是在类加载后直接初始化,不等静态方法调用的时候判空 再初始化,好处是防止多线程并发的情况下同时判为空多次创建对象,这样会带来很多问题,由于不是被初始化一次,那么第一次初始化后A线程使用了该对象,但是后面又被B线程初始化了,那么就会导致A线程中的操作是无效的,例如修改对象中的某些值等……
(1)
public class SingleTest {
private static SingleTest singleTest = new SingleTest();
private SingleTest(){
}
public static SingleTest getInstance(){
return singleTest;
}
}
(2)
public class SingleTest {
static class inner{
private static SingleTest singleTest = new SingleTest();
}
private SingleTest(){
}
public static SingleTest getInstance(){
return inner.singleTest;
}
}
2.懒汉式:顾名思义,相对于饿汉式,懒汉式就是在使用的时候即方法调用的时候再去做判空处理,为空再去创建对象,但是在饿汉中提出了会有线程不安全的问题,如下(1)所示就会出现线程不安全的情况
(1)
public class SingleTest {
private static SingleTest singleTest;
private SingleTest(){
}
public static SingleTest getInstance(){
if (null == singleTest){
singleTest = new SingleTest();
}
return singleTest;
}
}
(2)在(1)的基础上,在方法前使用synchronized来修饰,来防止并发的时候出现同时为空的情况
public class SingleTest {
private static SingleTest singleTest;
private SingleTest(){
}
public synchronized static SingleTest getInstance(){
if (null == singleTest){
singleTest = new SingleTest();
}
return singleTest;
}
}
(3)当然如(2)中所示代码,可以保证懒汉式的单例模式不会出现问题,但是问题的关键是将方法加锁,会导致多线程并发的情况代码不够优化,所以需要在(2)的基础上做如下修改,把实例化对象使用volatile来修饰,它的作用是,在多线程情况下,每个线程都有自己的内存空间,数据是线程隔离的,所以使用它,可以在数据发生变化的情况下及时的将变化的数据同步给其它的线程,除此(2)的问题就是在初始化的时候防止多线程的问题,那么我们可以将初始化的位置加锁,而不是将锁加到方法上,这样可以提高程序的性能,需要注意的是加锁中的代码,我们还要进行二次的判空处理,目的是虽然之前为空,但是再进行初始化的时候要进行判断是否已经被其它线程初始化完成了。
public class SingleTest {
private volatile static SingleTest singleTest;
private SingleTest(){
}
public static SingleTest getInstance(){
if (null == singleTest){
synchronized (SingleTest.class){
if (null == singleTest){
singleTest = new SingleTest();
}
}
}
return singleTest;
}
}
以上就是对单例模式的理解,平时都是使用饿汉式,写了懒汉式,是为了说明其中的问题,已经出现问题解决的办法。