码迷,mamicode.com
首页 > 其他好文 > 详细

单例模式学习

时间:2015-12-16 12:45:19      阅读:151      评论:0      收藏:0      [点我收藏+]

标签:java   多线程   单例模式   并发   

参考网站: 

1.Java 多线程学习笔记

2.简单且线程安全的两个单例模式java程序

3.Java多线程编程环境中单例模式的实现 (内部类实现多线程环境中的单例模式)


主要内容:

什么是单例模式?单例模式是一种设计模式,其设计的思路是:一个特殊的类,它只有一个实例,而且这个类提供了访问这个类的方法;


单例模式从实现上可分为饿汉式懒汉式:

饿汉式:

//单例模式————"饿汉式"的代码规范
class SingleHungry{
 //此处有关键字final修饰aSingleInstanceObjRef,则表明次对象不可修改,
 //虽然不要final也可以实现效果,但这样做更加规范。
 private static final SingleHungry aSingleInstanceObjRef = new Single();
 private SingleHungry() {}
 public SingleHungry getSingle() {
  return aSingleInstanceObjRef;
 }
}

优点:线程安全;

缺点:在未调用之前已经进行实例化,占用了相应的系统资源。


懒汉式:

//单例模式————"懒汉式"的代码
//下列代码是“线程不安全”的写法。
class SingleLanHan{
 //此处不能有关键字final,否则aSingleInstanceObjRef引用就无法被复制了,
 //因为它被定为以为一个常量null
 private static SingleLanHan aSingleInstanceObjRef = null;
 private SingleLanHan() {}
 public SingleLanHan getSingleLanHan(){
  if(aSingleInstanceObjRef == null) {  // A
   aSingleInstanceObjRef = new SingleLanHan();  // B
  }
  return aSingleInstanceObjRef;
  
 }
}

优点:在调用时才进行实例化;

缺点:线程不安全。原因:线程1和线程同时进入了A,线程1抢占了资源,执行了B,后来线程B也获得了资源,执行了B,这时候该类就被实例化两次,造成了线程不安全。


解决方案一(加锁):

//单例模式————"懒汉式"的代码
//下列代码是“线程不安全”的写法。
class SingleLanHan{
 //此处不能有关键字final,否则aSingleInstanceObjRef引用就无法被复制了,
 //因为它被定为以为一个常量null
 private static SingleLanHan aSingleInstanceObjRef = null;
 private SingleLanHan() {}
 public synchronized SingleLanHan getSingleLanHan(){
  if(aSingleInstanceObjRef == null) {  //  A
   aSingleInstanceObjRef = new SingleLanHan();
  }
  return aSingleInstanceObjRef;
  
 }
}

这个解决方案使用了synchronized关键字对来防止不同线程同时进入A处,由于单例模式只实例化一次,在往后的获取改实例的时候,都需要进行判断是否有其他的线程在占用着锁,效率低。


解决方法二(双重锁):

//单例模式————"懒汉式"的代码规范
class SingleLanHan{
 //此处不能有关键字final,否则aSingleInstanceObjRef引用就无法被复制了,
 //因为它被定为以为一个常量null
 private static SingleLanHan aSingleInstanceObjRef = null;
 private SingleLanHan() {}
 public SingleLanHan getSingleLanHan(){    
  if(aSingleInstanceObjRef == null) {     //A
   synchronized(SingleLanHan.class) {    
    if(aSingleInstanceObjRef == null) {
     aSingleInstanceObjRef = new SingleLanHan();
     return aSingleInstanceObjRef;
    }
   }
  }else {
   return aSingleInstanceObjRef;
  }
 }
}

这个解决方案在synchronized关键字之前加上了一条if语句(A处),在未实例化之前,synchronized的锁依然起作用,同时,在synchronized内部也需要一条判断语句,防止线程陆续进入synchronized块后重复实例化;而实例化后,它(A处)的作用就是隔离了synchronized块的操作。效率比方面方案一高。


解决方案三(内部类):

public class Singleton {
	static class SingletonHolder {
		static Singleton instance = new Singleton();
	}
	public static Singleton getInstance() {
		return SingletonHolder.instance;
	}
}

JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,同时,instance是在第一次加载SingletonContainer类时被创建的,而SingletonContainer类则在调用getInstance方法的时候才会被加载,因此也实现了lazy加载。


小小的单例模式还是有着这么大的学问,先记录下来,以备回顾只用。技术分享

本文出自 “NoobTidehunter” 博客,请务必保留此出处http://noobtidehunter.blog.51cto.com/10271860/1723442

单例模式学习

标签:java   多线程   单例模式   并发   

原文地址:http://noobtidehunter.blog.51cto.com/10271860/1723442

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!