设计模式-单例模式
饿汉式
类加载到内存后,就实例化一个单例,JVM保证线程安全。类就加载一次。
简单使用,推荐使用。
唯一缺点:不管用到与否,类加载时就完成实例化
package com.yc.designmode.singgleton;
/**
* 构造方法私有化,让别人无法 new 实例对象。
*/
public class Main01 {
private Main01(){};
public static final Main01 main01= new Main01();
public static Main01 getInstance (){
return main01;
}
public static void main(String[] args) {
Main01 instance = Main01.getInstance();
Main01 instance2 = Main01.getInstance();
System.out.println(instance ==instance2);
}
}
懒汉式(线程不安全版)
package com.yc.designmode.singgleton;
import com.yc.designmode.util.ThreadUtil;
import java.util.concurrent.TimeUnit;
/**
* 懒汉式
*/
public class Main02 {
private static Main02 instance;
private Main02 (){};
public static Main02 getInstance(){ //线程不安全
// public synchronized static Main02 getInstance(){ //线程安全 但是效率慢
if (instance ==null){
ThreadUtil.sleep(1000);
instance=new Main02();
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
Main02 instance = getInstance();
System.out.println(instance.hashCode());
}).start();
}
}
}
懒汉式(线程安全版,但是效率不高)
package com.yc.designmode.singgleton;
import com.yc.designmode.util.ThreadUtil;
import java.util.concurrent.TimeUnit;
/**
* 懒汉式
*/
public class Main02 {
private static Main02 instance;
private Main02 (){};
public synchronized static Main02 getInstance(){ //线程安全 但是效率慢
if (instance ==null){
ThreadUtil.sleep(1000);
instance=new Main02();
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
Main02 instance = getInstance();
System.out.println(instance.hashCode());
}).start();
}
}
}
懒汉式(线程安全版,双重验证)
使用synchronized 虽然线程安全,但是效率不高,我们进行改进
使用双重验证的形式进行判断是否是要 volatile 进行修饰 instance ?
当涉及到JIT (JIT 是 just in time 的缩写, 也就是即时编译编译器。)优化的时候,需要使用volatile,因为JIT优化,涉及到了指令重排序。因为没有进行JIT优化,所以本次不使用volatile 也可以
package com.yc.designmode.singgleton;
import com.yc.designmode.util.ThreadUtil;
import java.util.concurrent.TimeUnit;
/**
* 懒汉式
*/
public class Main02 {
private static Main02 instance;
private Main02 (){};
public static Main02 getInstance(){ //线程不安全
// 改进版
if (instance ==null){// 先进行判断,没有锁.效率高,即使多线线程访问到,后面也有锁进行保证安全,
//当返回第一个实例的时候,就不满足 == null条件,直接返回
synchronized (Main02.class) {
if (instance ==null){
instance=new Main02();
}
}
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
Main02 instance = getInstance();
System.out.println(instance.hashCode());
}).start();
}
}
}
静态内部类
package com.yc.designmode.singgleton;
import com.yc.designmode.util.ThreadUtil;
/**
* 懒汉式
*/
public class Main03 {
private Main03 (){};//构造方法私有化
public static class Main04 { //静态内部类 “内部类和静态内部类都是延时加载的,也就是说只有在明确用到内部类时才加载。只使用外部类时不加载。
public static final Main03 instance =new Main03();
}
public static Main03 getInstance(){
return Main04.instance;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
Main03 instance = getInstance();
System.out.println(instance.hashCode());
}).start();
}
}
}
枚举
java源码用到的单例模式
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
private Runtime() {}
}
单列模式注意事项是细节说明
① 单例模式保证了系统内存中该类只存在一个对象,节省了系统资源。对于一些需要频繁创建校会的对象,使用单例模式可以提高系统性能。
② 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new
单例模式使用的场景:需要频繁的创建和销毁对象、创建对象耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)
单例模式总结
什么是单例模式
所谓的单例模式,就是采取一定的方法保证在整个软件系统中,对某一个类只能存在一个对象实例,并且该类值提供一个取得其对象实例的方法(静态方法)
比如hibernate的sessionFactory,它充当数据存储源的代,并赋值创建Session对象。
单例模式的八种方法
饿汉式(静态常量) 推荐
饿汉式(静态代码块) 推荐
懒汉式(线程不安全)
懒汉式(线程安全,同步方法)
懒汉式(线程安全,同步代码块)
双重检查 推荐
静态内部类 推荐
枚举 推荐