目录
1.单例模式的认识
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
- 1.单例类必须自己创建自己的唯一实例。
- 2.单例类只能有一个实例。
- 3.单例类必须给所有其他对象提供这一实例。
- 4.包括两种类型:懒汉、饿汉
- 5.实现步骤:私有化构造函数、提供单例的方法
2.懒汉类型
懒加载,延迟对象创建,调用指定的方法创建对象
方式一:
通过私有化构造器,确保不被外部调用;构造方法,创建对象,但会存在线程不安全问题,一般使用synchronized 加锁解决,但在方法上加锁,会消耗性能,一般在指定对象上加锁,但在大量并发情况下,依旧会存在线程不安全问题。
/**
* 单例设计模式-懒汉实现
*/
public class SingletonLazy {
private static SingletonLazy singletonLazy;
/**
* 私有化构造函数
*/
private SingletonLazy() {
}
/**
* 测试方法
*/
public void test() {
System.out.println("单例模式-懒汉");
}
/**
* 第一种方式
* 对外暴露一个方法获取类的对象
* 线程不安全
*
* @return
*/
public static SingletonLazy getInstance1() {
if (singletonLazy == null) {
singletonLazy = new SingletonLazy();
}
return singletonLazy;
}
/**
* 第二种方式
* 通过加锁 synchronized 保证单例
* 缺点:影响性能
* 解决:锁的力度放小
*
* @return
*/
public static synchronized SingletonLazy getInstance2() {
if (singletonLazy == null) {
singletonLazy = new SingletonLazy();
}
return singletonLazy;
}
/**
* 第三种方式
* 将锁的力度放小
* @return
*/
public static SingletonLazy getInstance3() {
if (singletonLazy == null) {
//锁的力度放小
synchronized (SingletonLazy.class) {
singletonLazy = new SingletonLazy();
}
}
return singletonLazy;
}
}
方式二:
为了解决synchronized的弊端,避免线程不安全,我们使用双重检查锁定,这种方式既保证了线程安全,又实现了高性能。但由于指令重排的缘故,会导致创建的对象不完整。
/**
* 单例设计模式-懒汉实现
*/
public class SingletonLazy {
// private static SingletonLazy singletonLazy;
/**
* 私有化构造函数
*/
private SingletonLazy() {
}
/**
* 测试方法
*/
public void test() {
System.out.println("单例模式-懒汉");
}
/**
* 第一种方式
* DCL=双重检查锁定,在多线程情况下保持高性能
* 但仍然不安全——singletonLazy = new SingletonLazy(); 并不是原子性操作
* new对象的大体步骤:1.分配空间给对象; 2.在空间中创建对象;3.将对象赋值给引用
* 若线程顺序变为 1->3->2,会把值写到主内存,仍会被其他线程读取singletonLazy,但他不是完整的对象
* (指令重排)
* @return
*/
public static SingletonLazy getInstance1() {
if (singletonLazy == null) {//一重检查
//锁的力度放小
synchronized (SingletonLazy.class) {
if (singletonLazy == null) {//二重检查
singletonLazy = new SingletonLazy();
}
}
}
return singletonLazy;
}
}
方式三:
为了实现在高并发的情况下线程安全并且高性能,我们一般引入volatile关键字禁止指令重排
/**
* 单例设计模式-懒汉实现
*/
public class SingletonLazy {
private static volatile SingletonLazy singletonLazy;
/**
* 私有化构造函数
*/
private SingletonLazy() {
}
/**
* 测试方法
*/
public void test() {
System.out.println("单例模式-懒汉");
}
/**
* 禁止指令重排
* volatile:java提供的关键字,可以禁止指令重排
* @return
*/
public static SingletonLazy getInstance5() {
if (singletonLazy == null) {
//锁的力度放小
synchronized (SingletonLazy.class) {
if (singletonLazy == null) {
singletonLazy = new SingletonLazy();
}
}
}
return singletonLazy;
}
}
3.饿汉类型
- 提前创建对象
- 优点:实现简单,没有多线程同步问题
- 缺点:不管有没有使用,instance对象一致占用着内存
/**
* 单例设计模式-饿汉实现
*/
public class SingletonHungry {
//提前创建对象
public static SingletonHungry singletonHungry=new SingletonHungry();
/**
* 单例-私有化构造方法
*/
private SingletonHungry(){}
/**
* 测试方法
*/
public void test(){
System.out.println("单例模式-饿汉");
}
/**
* 调用指定的方法获取对象
* @return
*/
public static SingletonHungry getInstance(){
return singletonHungry;
}
}
注:
- 如果对象不大,且创建不复杂,直接用饿汉的方式即可~
- 其他情况采用懒汉方式