java单例模式(上)

三种实现方法详解:



懒汉式

public class SingletonDemo{

private static SingletonDemo s = new SingletonDemo();

private SingletonDemo(){
}

public static SingletonDemo getInstance(){
return s;
}

}

在类加载的时候得到一个实例化对象,java vm只要加载一了类以后,就不用再加载一次了,保证了实例只有一个。

public class Singleton2{

private Singleton2{

}

private static Singleton2 instance = null;

public synchonized static Singleton2 getInstance(){

if(instance == null){

instance = new Singleton2();

}

return instance;

}

}

由于是同步方法(在同一时间只能有一个线程访问,并且其他线程只有等到当前获得锁的线程执行完整个方法才能获得锁执行方法),对性能不是消耗大,能不能有更好的方法呢。实际上只需要将实例化对象的代码同步。这样就减少性能消耗。

private static SingletonDemo2 getInstance(){
if(instance == null){
synchronized (SingletonDemo2.class) {
instance = new SingletonDemo2(); 
}
}

return instance;
}

那上面的代码有没有问题呢,问题肯定是有的。当一个线程执行到if(instance == null)语句后,有可能它的时间片到期了,轮到其他线程执行,其他线程创建了对象并执行完成释放了锁。等到第一个线程再次获得时间片,继续执行,就会造成再次创建了新对象。


这样的情况是不可预料的,时间片的轮换是由操作系统控制。我们可以通过一下的代码发现问题。

private static SingletonDemo2 getInstance() throws Exception{
if(instance == null){

Thread.sleep(10);
synchronized (SingletonDemo2.class) {
instance = new SingletonDemo2(); 
}
}

return instance;
}

让第一个线程执行if(instance == null)后睡眠一会,让其他线程执行,这样就会出现上面的问题。

测试代码:

public static void main(String arg []) throws Exception{
class ThreadTest extends Thread{
private SingletonDemo2 ins1;
public void run(){
ins1 = SingletonDemo2.getInstance();
System.out.println(ins1); //看对象是不是同一个,第一种方法,比较打印的内存地址。
}
public SingletonDemo2 get(){
return ins1;
}
}
ThreadTest thread1 = new ThreadTest();
ThreadTest thread2 = new ThreadTest();
thread1.start();
thread2.start();

//第二中方法,equals比较

Thread.sleep(1000);//要等两个线程,执行完成才能比较
System.out.println(thread1.get().equals(thread2.get()));
}

执行结果:

C:\Users\twolight\Desktop>java SingletonDemo4
SingletonDemo4@1034bb5
SingletonDemo4@7f5f5897
false


这个问题如何解决呢。下面代码:

private static SingletonDemo2 getInstance(){
if(instance == null){
synchronized (SingletonDemo2.class) {

if(instance== null){

instance = new SingletonDemo2(); 

}
}
}

return instance;
}

里面再加一个判断,即便第一个线程再次获得时间片继续运行也不会创建对象。所以即便小小代码,也值得慢慢推敲的反思。这也就是懒汉式(Double check)
//懒汉模式(Double check)
class SingletonDemo2{
private static SingletonDemo2 instance;
private SingletonDemo2(){

}
private static SingletonDemo2 getInstance(){
if(instance == null){
synchronized (SingletonDemo2.class) {
if(instance == null){
instance = new SingletonDemo2(); 
}
}
}
return instance;
}

}

内部类实现:

class SingletonDemo3{
private SingletonDemo3(){

}
private static class Instance{
private static SingletonDemo3 s = new SingletonDemo3();
private Instance(){

}
private static SingletonDemo3 getInstance(){
return s;
}
}
private static SingletonDemo3 getInstance(){
return Instance.getInstance();
}
}
内部类的静态变量在类加载的时候初始化,所以能够保证对象的唯一性。并且只有到使用的时候才实例化对象。不是懒汉式加载的时候就实例化。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值