单例模式
一个单一的类,负责创建自己的对象,同时确保系统中只有单个对象被创建。
单例特点
•某个类只能有一个实例;(构造器私有)
•它必须自行创建这个实例;(自己编写实例化逻辑)
•它必须自行向整个系统提供这个实例;(对外提供实例化方法)
单例模式之懒汉式
顾名思义,饿汉式就是在需要使用实例的时候才创建实例
先创建一个普通的Person类,用于实现懒汉式
package com.nkym;
public class Person {
private String name;
private String age;
//保证一个类只有一个用于返回的对象
private static Person instance;
//私有化构造器,保证外部无法创建实例。
private Person(){
System.out.println("对象创建了");
}
//创建实例
public static Person getInstance(){
//如果instance为空则新 new 一个对象
if(instance==null){
instance = new Person();
}
//如果不为空,则直接返回
return instance;
}
}
测试
我们发现只有运行了一次构造器方法。并且获取的三个实例的引用都是相同的。指向的同一对象。
这样单例模式之懒汉式就设计好了。但是光这样是线程不安全的。当有并发出现时,会new出多个实列。
所以我们要给饿汉式加锁,让它变成线程安全的。
1、给getInstance方法枷锁(效率不高,适用于多线程环境)
这样每次调用getInstance都会上锁,效率不高
//给方法加锁。
public static synchronized Person getInstance(){
//如果instance为空则新 new 一个对象
if(instance==null){
instance = new Person();
}
//如果不为空,则直接返回
return instance;
}
2、方法内加锁(效率不高,适用于多线程环境)
同样每次调用getInstance都会上锁,效率不高
public static Person getInstance() {
//加synchronized锁
synchronized (Person.class) {
//如果instance为空则新 new 一个对象
if (instance == null) {
instance = new Person();
}
}
//如果不为空,则直接返回
return instance;
}
3、双重检验锁(适用于多线程,效率相对更高,推荐使用)
package com.nkym;/*
* @ClassName Person
* @Desc TODO
* @Author 19637
* @Date 2022/2/19 19:15
* @Version 1.0
*/
public class Person {
private String name;
private String age;
//------------------------有变化的地方-------------------------------------------
//volatile修饰成员变量 阻止指令重排序
private static volatile Person instance;
//私有化构造器,保证外部无法创建实例。
private Person() {
System.out.println("对象创建了");
}
//------------------------有变化的地方-------------------------------------------
//获取实例实例
public static Person getInstance() {
if (instance == null) {
//实例为空再加锁
synchronized (Person.class) {
if (instance == null) {
instance = new Person();
}
}
}
//如果不为空,则直接返回
return instance;
}
}
单例模式之饿汉式。
饿汉式就是在类加载的时候就创建实例。饿汉式本身就是线程安全的
package com.nkym;/*
* @ClassName Person
* @Desc TODO
* @Author 19637
* @Date 2022/2/19 19:15
* @Version 1.0
*/
public class Person {
private String name;
private String age;
//类加载就创建实例,加上final关键字,防止重复创建
private static final Person instance = new Person();
//私有化构造器,保证外部无法创建实例。
private Person() {
System.out.println("对象创建了");
}
//获取实例的方法
public static Person getInstance() {
return instance;
}
}
测试
我们发现只有运行了一次构造器方法。并且获取的三个实例的引用都是相同的。指向的同一对象。
这样单例模式之饿汉式就设计好了。并且不存在线程安全问题。