文章目录
单例模型
单例模式(Singleton Pattern)是Java中最简单的设计模式之一。类型的设计模式属于创建类型模式,它提供了一种创建对象的最佳方式。这种模式,可以直接访问自己的对象,该类负责创建对象,同时确保唯一的对象提供了唯一的对象
什么是单例模型?
创建型模式: 创建对象·
核心: 内存中只有唯一的一个对象(一般用在工具类中)
如何实现只有唯一的一个对象?
(1)单例模型——懒汉模式
懒汉模式是一开始没有引用对象,在调方法时创建对象。懒汉模式线程不安全。
package com.singleton;
/**
* 单例模型——懒汉模型
* @author wdy
*
*/
public class Singleton {
private static Singleton instance=null;//instance一开始没有引用任何对象
private Singleton() { //私有类跨文件不能创建对象
}
/*
* 当调用getInstance()方法,才建立instance的引用对象
*/
public static Singleton getInstance() {
if(instance==null) {
instance=new Singleton();
}
return instance;
}
}
package com.singleton;
/*
* 测试
*/
public class TestSingleton {
public static void main(String[] args) {
Singleton s1=Singleton.getInstance();
Singleton s2=Singleton.getInstance();
Singleton s3=Singleton.getInstance();
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
System.out.println(s1==s3);
}
}
结果显示 几个对象的哈希值相等 。引用也相同。是同一个对象。。说明只创建了一个对象
多线程情况下,懒汉模型是否线程安全?
测试一下多线程情况下是否安全
//通过线程池创建多线程
Executor pool = Executors.newCachedThreadPool();//创建线程池的工具类
for (int i = 0; i < 10; i++) {//10个线程
pool.execute(() -> { //lambda表达式。。线程代码部分
for (int j = 0; j < 10; j++) {//执行10次
System.out.println(Thread.currentThread().getName() + ": " + Singleton.getIntance().hashCode());
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
Lambda表达式:Lambda允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
(()-> { 线程代码 } )
执行结果如下,可见懒汉模型线程不安全。
pool-1-thread-6: 1335324870
pool-1-thread-10: 1335324870
pool-1-thread-1: 1967528551
pool-1-thread-8: 1335324870
pool-1-thread-4: 2087870959
pool-1-thread-9: 1335324870
pool-1-thread-7: 1335324870
懒汉模型线程不安全如何解决?
synchronized
直接在创建对象的getInstance()方法前加synchronized保证多线程安全。
ReentrantLock
在创建对象的getIntance()方法加线程锁
package com.singleton;
import java.util.concurrent.locks.ReentrantLock;
import javax.xml.crypto.dsig.keyinfo.RetrievalMethod;
/**
* 单例模型-懒汉模式线程不安全解决方法—— ReentranLock
* @author wdy
*
*/
public class Singleton {
private static Singleton instance = null; // instance 一开始没有引用任何对象
private final static ReentrantLock lock = new ReentrantLock();//创建锁对象
private Singleton() {
}
/**
* 调用getIntance()方法,才建立instance的引用对象
*
* @return
*/
public static Singleton getIntance() {
lock.lock();//线程锁
try {
if (instance == null) {
instance = new Singleton();
}
} finally {
lock.unlock();//释放锁
}
return instance;
}
}
双重检查模式
双重检查模式在方法加synchronized的基础上改进,对对象为空的情况进行双重检查, 保证线程安全。而且相比直接加synchronized,判断更精确,效率更高。
package com.singleton;
/*
* 单例模型 ——双重检查模式
*
* 保证线程安全
*/
public class Singleton02 {
private static Singleton02 instance;
private Singleton02() {}
public static Singleton02 getInstance() {
if(instance==null) { //对象为空 再锁
synchronized (Singleton02.class) {
if(instance==null) { //再次判断
instance=new Singleton02();
}
}
}
return instance;
}
}
(2)单例模型——饿汉模式
饿汉模式一开始就造好对象,是由JVM来保证线程安全。
用上述的测试代码测试,结果饿汉模式显示线程安全。
package com.singleton;
/**
* 单例:饿汉模式
* @author Administrator
*
*/
public class Singleton2 {
private final static Singleton2 instance= new Singleton2();//JVM保证线程安全
private Singleton2() {}
public static Singleton2 getIntance() {
return instance;
}
}