单例模式是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("测试枚举");
}
}
以上就是一些单例模式常用的写法
单例模式的适用场景就是当一个类被重复多次使用的时候,那这个类就可以用单例来写,常用的多就是体现在一些工具类上面。