一:单例模式的概述
单例模式是在 java中一种常见的设计模式,这种类型的设计模式属于一种创建型模式,这种模式提供了一个创建对象的最佳模式,在模式中一个类只能创建一个对象,该类负责创建自己的对象,并且只有一个实例,私有构造方法,即表示不能再类的外部实例化该类的对象,只能通过该类提供的公有方法来返回该类的一个实例对象。
二:单例类的基础
单例模式的基础:一个 类只有一实例,并为整个系统提供一个全局访问点,
结构:
类图分为三部分:
类名,属性,方法,
《》表示注释信息,+ 代表public,-代表private,#代表 protected,
下划线代表 属相或方法为 静态,
单例模式三要素:
私有的构造方法,
指向自己实例的私有静态引用,
以自己实例为返回类型的公有静态方法,
三:单例类的实现
1:两种实现方式
我们根据对单例类对象的两种加载方式 ,分为立即加载,和延迟加载,对应两种模式;为饿汉模式和懒汉模式,
2:饿汉模式的实现
根据定义:饿汉模式即为在类创建的时候,就已经将类的实例对象创建好了,饿汉模式在多线程的模式下为安全模式,在多线程的情况下 也保证只有一个实例对象。
public class SingletonDemo1 {
//指向自己实例的私有静态 引用
private static SingletonDemo1 sing=new SingletonDemo1();
// 私有的构造方法
private SingletonDemo1(){}
//以自己实例为返回值的静态 公有方法
public static SingletonDemo1 getInstance(){
return sing;
}
}
3:懒汉模式(线程不安全的实现)
懒汉模式即为只有在我们需要的时候才会创建实例对象,延迟加载
public class SingletonDemo2 {
// 指向自己实例的私有静态引用
private static SingletonDemo2 sing;
// 私有的构造方法
private SingletonDemo2(){}
// 以自己实例为返回值的静态公有方法
public static SingletonDemo2 getInstance(){
if (sing==null){
sing= new SingletonDemo2();
}
return sing;
}
}
3:在多线程环境下的测试
public class Test {
public static void main(String[] args) {
// 开启 10 个 线程
Thread [] threads= new Thread[10];
for(int i=0;i<threads.length;i++){
threads[i]=new TestThread();
}
for(int i=0;i<threads.length;i++){
threads[i].start();
}
}
}
class TestThread extends Thread{
public void run(){
int hash =SingletonDemo1.getInstance().hashCode();
System.out.println(hash);
}
}
在多线程的环境下,我们可以看到,饿汉模式只返回了同一个对象,
懒汉模式可能会返回多个实例,即线程不安全。
三:懒汉模式多线程下安全的实现
1:使用synchronized 方法
public class SingletonDemo3 {
//指向 自己实例的私有静态 引用
private static SingletonDemo3 sing;
// 私有构造方法
private SingletonDemo3(){
}
// 以自己实例 为 返回值的静态 公有方法 临界 对临界资源加锁
public static synchronized SingletonDemo3 getInstance(){
if(sing == null){
sing =new SingletonDemo3();
}
return sing;
}
}
二:使用同步代码块
public class SingletonDemo4 {
// 指向自己实例的私有静态引用
private static SingletonDemo4 sing;
// 私有构造方法
private SingletonDemo4 (){}
// 以自己实例为 返回值 的静态 公有方法 临界资源加锁 同步 代码块
public static SingletonDemo4 getInatance(){
synchronized(SingletonDemo4.class){
if(sing == null){
sing =new SingletonDemo4();
}
return sing;
}
}
}
3:使用私有静态内部类来实现延迟加载
public class SingletonDemo5 {
// 私有 静态 内部类 实现 延迟 加载 即 需要 时 加载
private static class Handle{
private static SingletonDemo5 sing=new SingletonDemo5();
}
// 私有构造方法
private SingletonDemo5(){}
// 返回 实例 对象的方法
public static SingletonDemo5 getInstance(){
return Handle.sing;
}
}
4:使用双重检查机制
public class SingletonDemo6 {
// 被 volatile 关键字修饰的 对象实例
private static volatile SingletonDemo6 sing;
// 私有的构造 方法
private SingletonDemo6(){}
// 返回 对象 实例 ,双重检查 机制
public static SingletonDemo6 getInstance(){
if(sing ==null){
synchronized(SingletonDemo6.class){
// 只有在 第一次 创建 时 才 会执行
if(sing ==null){
sing= new SingletonDemo6();
}
}
}
return sing;
}
}
5:使用ThreadLocal 实现懒汉式单例
public class SingletonDemo7 {
// ThreadLocal 线程局部变量
private static ThreadLocal<SingletonDemo7> threadLocal = new ThreadLocal<SingletonDemo7>();
private static SingletonDemo7 sing = null; //
private SingletonDemo7(){}
public static SingletonDemo7 getSingleton4(){
if (threadLocal.get() == null) { // 第一次检查:该线程是否第一次访问
createSingleton4();
}
return sing;
}
public static void createSingleton4(){
synchronized (SingletonDemo7.class) {
if (sing== null) { // 第二次检查:该单例是否被创建
sing = new SingletonDemo7(); // 只执行一次
}
}
threadLocal.set(sing); // 将单例放入当前线程的局部变量中
}
}