单例模式的基础概念
单例模式是什么
在整个系统的运行过程中,一个类只能拥有一个实例供全局使用;
单例模式使用场景
- 共享某个资源,例如:配置文件、日志文件、数据库连接池、驱动、缓存等
- 全局工具类,例如:计数器、唯一序列号、md5等
- java核心类,例如:java.lang.Runtime,java.awt.Desktop
单例模式代码编写
满足满足的两点要求
- 在JVM中,只能存在唯一实例
- 必须提供全局可以访问的点
饿汉模式
源代码
package singleton;
/**
* @author : freedom
* @Description : 饿汉式单例模式即类加载立即创建对象,不用等到使用时才创建
* @Creation Date: 2019-11-21 8:01 上午
*/
public class SimpleSingleton {
/**
* 声明一个私有的不可更改的单例实例
*/
private static final SimpleSingleton simpleSingleton = new SimpleSingleton();
/**
* 私有化默认构造方法,不允许外部调用
*/
private SimpleSingleton() {
}
/**
* 通过静态方法获取实例
*/
public static SimpleSingleton getInstance() {
return simpleSingleton;
}
}
说明
饿汉模式即只要类加载,就创建唯一实例,不管用不用的上。
优点:线程安全,实现简单
缺点:不使用也创建,浪费内存
懒汉模式
源代码
package singleton;
/**
* @author : freedom
* @Description : 懒汉单例模式即只有在调用时才被实例化
* @Creation Date: 2019-11-21 8:21 上午
*/
public class LazySingleton {
/**
* 私有化静态对象实例
*/
private static LazySingleton lazySingleton = null;
/**
* 私有化构造方法
*/
private LazySingleton() {
}
/**
* 判断实例是否为空时,创建实例对象。只有在调用getInstance()方法时,才会创建单例对象。 此方法单线程是安全的,多线程不安全;多个线程同时调用会创建多个不同的单例
*
* @return 单例对象
*/
public static LazySingleton getInstance() {
if (lazySingleton == null) {
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
//======================华丽的分割线===========================
//以下是多线程调用时,解决线程不安全问题
/**
* 采用方法加锁方式解决
*/
public static synchronized LazySingleton getInstance1() {
if (lazySingleton == null) {
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
/**
* 采用synchronized块解决线程安全问题,但是此种方式还是存在两个或者多个线程同时进入if里的问题
*/
public static LazySingleton getInstance2() {
if (lazySingleton == null) {
synchronized (LazySingleton.class) {
lazySingleton = new LazySingleton();
}
}
return lazySingleton;
}
/**
* 采用双重验证方式解决线程不安全的问题
*/
public static LazySingleton getInstance3() {
if (lazySingleton == null) {
synchronized (LazySingleton.class) {
if (lazySingleton == null) {
lazySingleton = new LazySingleton();
}
}
}
return lazySingleton;
}
}
说明
懒汉模式:唯一实例在被调用时才创建
优点:只在被掉用时才初始化,单线程是安全的
缺点:多线程不安全,解决线程不安全问题,会降低执行效率
静态内部类单例模式
源代码
package singleton;
/**
* @author : freedom
* @Description : 线程安全的单例模式类(即满足使用时才加载也满足线程安全)
* @Creation Date: 2019-11-21 12:35 下午
*/
public class ThreadSafeSingleton {
/**
* 私有化默认的构造方法
*/
private ThreadSafeSingleton() {
}
/**
* 静态内部类
*/
public static class SingletonHelper {
/**
* 私有化静态内部类的属性
*/
private static final ThreadSafeSingleton threadSafeSingleton = new ThreadSafeSingleton();
}
/**
* 提供全局访问的静态方法
*/
public static ThreadSafeSingleton getInstance() {
return SingletonHelper.threadSafeSingleton;
}
}
说明
静态内部类单例模式:只有被调用时才被创建唯一实例,并且多线程安全。单例模式推荐写法。
测试类
源代码
package singleton;
/**
* @author : freedom
* @Description : 单例模式测试类
* @Creation Date: 2019-11-21 8:06 上午
*/
public class SingletonTest {
public static void main(String[] args) {
// SimpleSingleton simpleSingleton1=SimpleSingleton.getInstance();
// SimpleSingleton simpleSingleton2=SimpleSingleton.getInstance();
// if(simpleSingleton1.hashCode()==simpleSingleton2.hashCode()){
// System.out.printf("获取到的两个实例是同一个实例");
// }else{
// System.out.printf("获取到的两个实例不是同一个实例");
// }
// LazySingleton lazySingleton1=LazySingleton.getInstance();
// LazySingleton lazySingleton2=LazySingleton.getInstance();
// if(lazySingleton1.hashCode()==lazySingleton2.hashCode()){
// System.out.printf("获取到的两个实例是同一个实例");
// }else{
// System.out.printf("获取到的两个实例不是同一个实例");
// }
ThreadSafeSingleton lazySingleton1=ThreadSafeSingleton.getInstance();
ThreadSafeSingleton lazySingleton2=ThreadSafeSingleton.getInstance();
if(lazySingleton1.hashCode()==lazySingleton2.hashCode()){
System.out.printf("获取到的两个实例是同一个实例");
}else{
System.out.printf("获取到的两个实例不是同一个实例");
}
}
}
运行结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aVdaSOHw-1574465125622)(evernotecid://AAA42DFC-EC45-4768-B516-25846DA75603/appyinxiangcom/12441645/ENResource/p1868)]