设计模式之单例模式

这是我写的第一篇文章,目的是为了自己加深理解和以后的用的时候看看,希望各位大神指点不当之处,让我这个小小菜鸟进一步的学习,谢谢!!

今天我遇到了一个题,就是单例模式的,单例模式创建的是同一个对象吗?在多线程中是不是呢?想要完美应该怎么写单例呢?

首先说说单例模式(Singleton Pattern):

           目的:单例的作用就是创建一个唯一的实例,防止对象泛滥。

           分类:单例一般分为懒汉式和饿汉式

                      1、懒汉式:

class LoveSQQ{
	private static LoveSQQ sqq = null;
	private LoveSQQ(){
	}
	public static LoveSQQ getLoveSQQ(){
		if(sqq == null){
			sqq = new LoveSQQ();
		}
		return sqq;
}



                     2、饿汉式:

public class LoveSQQ{
       private static LoveSQQ sqq = new LoveSQQ();
       private LoveSQQ(){}
       public static LoveSQQ getLoveSQQ(){
              return sqq;
        }
     
}


这是两种相信大家都熟悉,我想说的就是这两种模式是不是线程安全的呢? 首先我测试了第一种懒汉式的

public class SingletonTest {

	public static void main(String[] args) {
	
		
		for(int i=0;i<10;i++){
			new Thread(new Runnable(){
				public void run() {
					while(true){
						try {
							Thread.sleep(10000);
							System.out.println(Thread.currentThread().getName()+"----"+LoveSQQ.getLoveSQQ());
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				};
			}).start();
			
			new Thread(new Runnable(){
				public void run() {
					while(true){
						try {
							Thread.sleep(1000);
							System.out.println(Thread.currentThread().getName()+"----"+LoveSQQ.getLoveSQQ());
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				};
			}).start();
		}
		
	}
	
}

class LoveSQQ{
	private static LoveSQQ sqq = null;
	private LoveSQQ(){
	}
	public static LoveSQQ getLoveSQQ(){
		if(sqq == null){
			System.out.println("创建实例");
			sqq = new LoveSQQ();
		}
		return sqq;
}                                                                                                                                                                                                                                                                得到结果:创建实例
创建实例
创建实例
Thread-5----com.wwy.thread.LoveSQQ@e0e1c6
创建实例
Thread-9----com.wwy.thread.LoveSQQ@6ca1c
创建实例
Thread-11----com.wwy.thread.LoveSQQ@1bf216a
创建实例
Thread-7----com.wwy.thread.LoveSQQ@12ac982
Thread-3----com.wwy.thread.LoveSQQ@10d448
Thread-13----com.wwy.thread.LoveSQQ@1389e4
Thread-17----com.wwy.thread.LoveSQQ@1389e4
Thread-15----com.wwy.thread.LoveSQQ@1389e4

 

这说明上面写的懒汉式是线程不安全的,为什么呢?

分析:在多个线程来执行上面的那个LoveSQQ类的getLoveSQQ()方法的时候,当线程1进去的时候创建了一个实例,但还没终止那个方法的时候,cpu切换了另一个线程,线程2有创建了一个实例,就出现了上面的结果。造成这个结果的原因就是sqq=new LoveSQQ();这句不具有原子性(原子性:就是一句话要么执行,要么不执行,不可分的),而它在jvm中是分了好几步来做的,大致分为三类:          

     1、给sqq实例分配空               

     2、初始化sqq构造器          

     3、将sqq对象指向分配的内存空(注意这里sqq就不是null了 )          

就是这些步骤造成了它不具有原子性,也就线程不安全了接下来要考虑线程安全的问题,我首先想到的就是synchronized,实现同步互斥不就可以了吗?看下面的代码:

class LoveSQQ{
	private static LoveSQQ sqq = null;
	private LoveSQQ(){
	}
	public synchronized static LoveSQQ getLoveSQQ(){
		if(sqq == null){
			System.out.println("创建实例");
			sqq = new LoveSQQ();
		}
		return sqq;
}

这样虽然是线程安全了但是同样也很大的降低了它的性能。写成同步代码块是不是能提高一下性能呢?

class LoveSQQ{
	private static LoveSQQ sqq = null;
	public synchronized static LoveSQQ getLoveSQQ(){
		if(sqq == null){
			synchronized(LoveSQQ.class){
			   if(sqq == null){
				   sqq = new LoveSQQ();
			   }
			}
		}
		return sqq;
	}
}


这样写可以至少比上面的性能好了一点。但肯定不是最完美的,在网上我看到一种使用静态内部类的

class LoveSQQ{
	private LoveSQQ(){}
	private static class Singleton{
		private final static LoveSQQ sqq = new LoveSQQ(); 
	}
	public static LoveSQQ getLoveSQQ(){
		return Singleton.sqq;
	}
}


这一种性能就比较好多了。说到这里就让我们先来看看饿汉式,通过前面的测试得到饿汉式他是线程安全的,为什么呢?因为它里面的实例相当于一个静态常量,在类初始化的时候就初始化了,每个线程调用的都是同一个实例。而使用静态内部类的和饿汉式很相似,它是通过内部类把饿汉式改为了懒汉式,灵活性大大的提高了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值