单例设计模式
单例模式,也叫单子模式,是一种常用的软件设计模式,属于创建型模式的一种。 在应用这个模式时,单例对象的类必须保证只有一个实例存在。 许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。
v1-饿汉式
/**
*饿汉式
* 类加载到内存之后就实例化一个单例,JVM保证线程安全
* 简单实用
* 唯一缺点:不管用到与否,类加载时就完成实例化
*/
public class Mgr01 {
private static final Mgr01 INSTANCE = new Mgr01();
//私有化构造方法
private Mgr01() {
}
public static Mgr01 getInstance() {
return INSTANCE;
}
public static void main(String[] args) {
Mgr01 mgr01 = Mgr01.getInstance();
Mgr01 mgr02 = Mgr01.getInstance();
System.out.println(mgr01==mgr02);
}
}
v2-懒汉式-lazyloading
/**
* lazy loading
* 虽然达到了按需初始化的目的,但是带来了线程不安全的问题
*/
public class Mgr02 {
private static Mgr02 INSTANCE;
//私有化构造方法
private Mgr02() {
}
public static Mgr02 getInstance() {
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr02();
}
return INSTANCE;
}
public static void main(String[] args) {
/*
如果哈希码不同说明获取的不是同一个类的同一个对象,出现了多线程访问的不安全问题
*/
for (int i = 0; i < 100; i++) {
new Thread(()-> System.out.println(Mgr02.getInstance().hashCode())).start();
}
}
}
v3-lazyloading+lock
/**
* lazy loading + 锁
* 虽然达到了按需初始化的目的,但是带来了线程不安全的问题
* 在方法上加了synchronized之后 效率变低
*/
public class Mgr03 {
private static Mgr03 INSTANCE;
//私有化构造方法
private Mgr03() {
}
public static synchronized Mgr03 getInstance() {
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr03();
}
return INSTANCE;
}
public static void main(String[] args) {
/*
如果哈希码不同说明获取的不是同一个类的同一个对象,出现了多线程访问的不安全问题
*/
for (int i = 0; i < 100; i++) {
new Thread(()-> System.out.println(Mgr03.getInstance().hashCode())).start();
}
}
}
v4-lazyloading+synchronized代码块
+/**
* lazy loading + 锁
* 虽然达到了按需初始化的目的,但是带来了线程不安全的问题
* 在执行创建对象的部分加了synchronized代码块 线程还是不安全
*/
public class Mgr04 {
private static Mgr04 INSTANCE;
//私有化构造方法
private Mgr04() {
}
public static Mgr04 getInstance() {
if (INSTANCE == null) {
synchronized (Mgr04.class){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr04();
}
}
return INSTANCE;
}
public static void main(String[] args) {
/*
如果哈希码不同说明获取的不是同一个类的同一个对象,出现了多线程访问的不安全问题
*/
for (int i = 0; i < 100; i++) {
new Thread(()-> System.out.println(Mgr04.getInstance().hashCode())).start();
}
}
}
v5-doublecheck
+/**
* 双重检查
*/
public class Mgr05 {
private static volatile Mgr05 INSTANCE;//JIT 指令重排的问题
//私有化构造方法
private Mgr05() {
}
public static Mgr05 getInstance() {
if (INSTANCE == null) {
synchronized (Mgr05.class){
if (INSTANCE ==null){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr05();
}
}
}
return INSTANCE;
}
public static void main(String[] args) {
/*
如果哈希码不同说明获取的不是同一个类的同一个对象,出现了多线程访问的不安全问题
*/
for (int i = 0; i < 100; i++) {
new Thread(()-> System.out.println(Mgr05.getInstance().hashCode())).start();
}
}
}
v6-静态内部类
+/**
* 静态内部类
* JVM保证单例
* 加载外部类时不会加载内部类,只有在调用getInstance的时候才会加载内部类,内部类实例化对象,这样实现了懒加载
*/
public class Mgr06 {
//私有化构造方法
private Mgr06() {
}
//静态内部类初始化外部类对象
private static class Mgr06Holder {
private static Mgr06 INSTANCE = new Mgr06();
}
public static Mgr06 getInstance() {
return Mgr06Holder.INSTANCE;
}
public static void main(String[] args) {
/*
如果哈希码不同说明获取的不是同一个类的同一个对象,出现了多线程访问的不安全问题
*/
for (int i = 0; i < 100; i++) {
new Thread(() -> System.out.println(Mgr06.getInstance().hashCode())).start();
}
}
}
v7-枚举单例
+/**
* 不仅可以解决线程同步还可以防止反序列化
* 枚举单例
*/
public enum Mgr07 {
INSTANCE;
public static void main(String[] args) {
/*
如果哈希码不同说明获取的不是同一个类的同一个对象,出现了多线程访问的不安全问题
*/
for (int i = 0; i < 100; i++) {
new Thread(() -> System.out.println(Mgr07.INSTANCE.hashCode())).start();
}
}
}
将propertyManager和ResourceManager修改成单例,保证只能有一个对象
property
static Properties props = new Properties();
private static final Properties props = new Properties();
private PropertyManager(){}
resource
private static final ResourceManager INSTANCE = new ResourceManager();
private ResourceManager(){}
public static ResourceManager getInstance(){
return INSTANCE;
}