天天看点

设计模式之单例模式写法详解

单例模式是Java设计模式中最为常见的一种设计模式,在很多框架中也使用到单例模式写法。

就比如说,在项目中有一个类,他在项目的很多地方都被使用到的时候,你就需要去初始化这个类去调用对应的方法,每次初始化都是一个新的对象,就导致内存的浪费,增加GC负担,单例模式就解决了这种问题。

单例模式的原则是:一个对象只允许有一个实例存在。

单例模式主要注意两个地方:

    1.私有化构造方法

    单例模式必须私有化构造方法,防止外部直接进行初始化对象。

    2. 必须定义一个静态方法,返回该实例

    私有化构造方法后,外部就不能通过new来创建对象,但是我们向外部开放一个静态的方法供外部调用。

接下来就给大家详细介绍单例模式中常见几种写法

1. 懒汉式(线程不安全)

但是这种写法,在多线程环境下的时候,是不安全的,这种方式是不推荐用的。

public class Car {
	
	private  String name;//名称
	private  Double  price;//价格
	
	private static Car car=null;

	private Car() {//写单例模式-最重要的是私有化构造方法
		
	}
	
	public  static Car  getInstance() {
		if(car==null) {
			car =new Car();
		}
		return  car;
	};
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Double getPrice() {
		return price;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	
}
           

2. 懒汉式(线程安全)

这种方式在上面写法的基础上加入了synchronized 关键字,加锁使他线程不安全变得线程安全了,但是在效率上变慢了,这种方式也不推荐使用

public class Car {
	
	private  String name;//名称
	private  Double  price;//价格
	private static Car car=null;

	private Car() {//写单例模式-最重要的是私有化构造方法
		
	}
	
	public  static synchronized Car  getInstance() {
		if(car==null) {
			car =new Car();
		}
		return  car;
	};
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Double getPrice() {
		return price;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	
}
           

3. 饿汉式(静态常量)

这种写法不会出现线程不安全问题,因为他在类加载的时候就实例化好了,这种方式推荐使用,但不是最好,因为如果系统里面有很多这种类,都是在加载的时候就实例化好了, 但是!!如果说我有一部类并没有使用到,你也给他实例化了,是不是会造成内存的浪费,那么我能不能在需要使用的时候在给他创建呢?

public class Car {

	private  String name;//名称
	private  Double  price;//价格
	
	private final static Car car=new Car();

	private Car() {//写单例模式-最重要的是私有化构造方法
		
	}
	
	public  static  Car  getInstance() {
		
		return  car;
	};
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Double getPrice() {
		return price;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	
}
           

4. 饿汉式(静态代码块)

这种方式其实和上面写法差不多,只不过是把类加载初始化实例的过程放在了静态代码块中,优缺点和上面一样。

public class Car {

	private  String name;//名称
	private  Double  price;//价格
	
	private static Car car=null;
	
	static {
		car =new Car();
	}

	private Car() {//写单例模式-最重要的是私有化构造方法
		
	}
	
	public  static  Car  getInstance() {
		
		return  car;
	};
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Double getPrice() {
		return price;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	
}
           

5. 双重效检锁(推荐使用)

加入两重判断,在加锁保证线程安全,推荐使用。静态变量需要volatile关键字进行修饰,保证线程安全。

public class Car {

	private  String name;//名称
	private  Double  price;//价格
	
	private static volatile Car car=null;//volatile一定要加这个关键字,保证线程安全
	

	private Car() {//写单例模式-最重要的是私有化构造方法
		
	}
	
	public  static  Car  getInstance() {
		
		if(car==null) {//一重判断
			synchronized (Car.class) {//加锁
				if(car ==null) {//二重判断
					car =new Car();
				}
			}
		}
		
		return  car;
	};
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Double getPrice() {
		return price;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	
}
           

6. 静态内部类

这种方式使用JVM来帮我们保证了线程的安全性,因为在类进行初始化的时候,别的线程是无法进入的,从而保证了线程的安全性,在Car类进行加载的时候,内部类是不会加载的,所以只有当调用getInstance方法的时候,对象才会被初始化。也比较推荐使用

public class Car {

	private  String name;//名称
	private  Double  price;//价格
	
	private Car() {//写单例模式-最重要的是私有化构造方法
		
	}
	
	private  static class CarSingle{//静态内部类
		private  static final  Car car =new Car();
	}
	
	public  static  Car  getInstance() {
		return  CarSingle.car;
	};
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Double getPrice() {
		return price;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	
}
           

7. 枚举(推荐使用)

在jdk1.5以上加入了枚举的方式,可以通过这种方式来实现单例模式,它不仅解决了多线程的安全问题,代码上还非常的简洁,优雅。

public enum Car {
		getInstance;
	
	public void show() {
		System.out.println("测试枚举");
	}
}
           

以上就是一些单例模式常用的写法

单例模式的适用场景就是当一个类被重复多次使用的时候,那这个类就可以用单例来写,常用的多就是体现在一些工具类上面。