Java 单例设计模式

单例设计模式是Java中最常见也是最简单的一种设计模式,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。
单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例。
它可以解决的问题是:可以保证一个类在内存中的对象的唯一性,在一些常用的工具类、线程池、缓存,数据库,账户登录系统、配置文件等程序中可能只允许我们创建一个对象,一方面如果创建多个对象可能引起程序的错误,另一方面创建多个对象也造成资源的浪费。

单例模式的关键就是保证对象的唯一性:
(1)不允许其他程序用new对象
因为new就是开辟新的空间,在这里更改数据只是更改的所创建的对象的数据,如果可以new的话,每一次new都产生一个对象,这样肯定保证不了对象的唯一性。
(2)在该类中创建对象
因为不允许其他程序new对象,所以这里的对象需要在本类中new出来
(3)对外提供一个可以让其他程序获取该对象的方法
因为对象是在本类中创建的,所以需要提供一个方法让其它的类获取这个对象。

将以上三步转化为程序语言就是:
(1)私有化该类的构造函数
(2)通过new在本类中创建一个本类对象
(3)定义一个公有的方法,将在该类中所创建的对象返回

单例模式的几种实现方式:1.饿汉式 2.懒汉式 3.双重校验锁 4.静态内部类 5.枚举
1.饿汉式【可用】
public class SingleDemo{
	private static SingleDemo instance=new SingleDemo();
	private SingleDemo(){};
	public static SingleDemo getInstance(){
		return instance;
	}
}

访问方式:

 SingleDemo instance=SingleDemo.getInstance();

优缺点:没有加锁,执行效率较高;类加载的时候就完成了实例化,避免了线程同步问题,但是可能会用不到这个实例,造成内存的浪费。

2.懒汉式【线程不安全,不可用】
public class SingleDemo{
   private static SingleDemo instance=null;
   private SingleDemo(){};
   public static SingleDemo getInstance(){
   	if(instance==null){
   		instance=new SingleDemo();
   	}
   	return instance;
   }
}

为什么会存在线程安全问题呢?在运行过程中可能会存在这样一种情况:有多个线程去调用getInstance方法来获取SingleDemo的实例,那么就有可能发生这样一种情况当第一个线程在执行if(instance==null)这个语句时,此时instance是为null的进入语句。在还没有执行instance=new SingleDemo()时(此时instance是为null的)第二个线程也进入if(instance==null)这个语句,因为之前进入这个语句的线程中还没有执行instance=new SingleDemo(),所以它会执行instance=new SingleDemo()来实例化SingleDemo对象,因为第二个线程也进入了if语句所以它也会实例化SingleDemo对象。这样就导致了实例化了两个SingleDemo对象。所以单例模式的懒汉式是存在线程安全问题的。

懒汉式改进1:【线程安全,效率低,不推荐使用】
 public class SingleDemo{
	private static SingleDemo instance=null;
	private SingleDemo(){};
	public static synchronized SingleDemo getInstance(){
		if(instance==null){
			instance=new SingleDemo();
		}
		return instance;
	}
}

每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。

懒汉式改进2:【线程不安全,不可用】
 public class SingleDemo{
	private static SingleDemo instance=null;
	private SingleDemo(){};
	public static SingleDemo getInstance(){
		if(instance==null){
		synchronized(SingleDemo.class){
				instance=new SingleDemo();
			}
		}
		return instance;
	}
}

当一个线程还没有实例化SingleDemo时另一个线程执行到if(instance==null)这个判断语句时就会进入if语句,虽然加了锁,但是等到第一个线程执行完instance=new SingleDemo()跳出这个锁时,另一个进入if语句的线程同样会实例化另外一个SingleDemo对象,线程不安全的原理跟懒汉式类似!

3.单例模式懒汉式双重校验锁【推荐用】
public class SingleDemo {
	/**
	 * 懒汉式变种,属于懒汉式中最好的写法,保证了:延迟加载和线程安全
	 */
	private static SingleDemo instance=null;
	private SingleDemo() {};
	public static SingleDemo getInstance(){
		 if (instance == null) {  //双重判断,减少锁判断次数
	          synchronized (SingleDemo.class) {  
	              if (instance == null) {  
	            	  instance = new SingleDemo();  
	              }  
	          }  
	      }  
	      return instance;  
	}
}

访问方式

SingleDemo instance=SingleDemo.getInstance();

优缺点:线程安全,延迟加载,效率较高

4.静态内部类【推荐】
public class SingleDemo {
	private SingleDemo() {};
	private static class Inner{
		private static SingleDemo instance=new SingleDemo();
	}
	public static SingleDemo getInstance() {
		return Inner.instance;
	}
}

访问方式:

SingleDemo instance=SingleDemo.getInstance();

优缺点:线程安全,延迟加载,效率高。
饿汉式只要是SingleDemo类被装载就是实例化,没有lazy-loading,静态内部类在被装载时并不会立即实例化,调用getInstance方法,才会装载Inner类,从而完成SingleDemo的实例化。
类的静态属性只会在第一次加载类的时候初始化,jvm保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

5.枚举【极推荐】
public enum SingleDemo {
	instance;
	private SingleDemo() {};
	public void method() {
	}
}

访问方式

SingleDemo.instance.method();

优缺点:避免了多线程同步问题;同时防止反序列化重新创建新的对象。

如有错误,欢迎指正。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值