设计模式之单例模式
Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”
饿汉式:类加载的时候就实例化,并且创建单例对象。
//饿汉式 :类加载的时候就实例化,并且创建单例对象。
public class Hungry {
public Hungry() {
System.out.println(Thread.currentThread().getName()+"ok");
}
private static final Hungry HUNGRY = new Hungry();
public static Hungry getInstance() {
return HUNGRY;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
Hungry.getInstance();
}).start();
}
}
}
懒汉式,双重检测锁模式的懒汉式单例,DCL模式
//懒汉式
public class LazyMan {
public LazyMan() {
System.out.println(Thread.currentThread().getName()+"ok");
}
private volatile static LazyMan lazyMan;
//双重检测锁模式的懒汉式单例,DCL模式
public static LazyMan getInstance() {
if(lazyMan == null) {
synchronized (LazyMan.class) {
if(lazyMan == null) {
lazyMan = new LazyMan();//不是原子性操作
/**
* 不是原子性操作有三步操作
* 1、分配内存空间
* 2、执行构造方法,初始化对象
* 3、把这个对象指向这个空间
*
* 可能发生执行重排
* 比如本来我们期望是 123
* 结果走成 132
* 解决方法:volatile关键字
*/
}
}
}
return lazyMan;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
LazyMan.getInstance();
}).start();
}
}
}
注意:反射可以破坏单例,枚举类实现单例可以防止反射破坏单例
一定程度上,解决反射破坏单例
//懒汉式
public class LazyMan {
private static boolean xy = false;
public LazyMan() {
synchronized(LazyMan.class) {
if(xy == false) {
xy = true;
}else {
throw new RuntimeException("不要试图用反射破坏单例");
}
/* if(lazyMan != null) {
throw new RuntimeException("不要试图用反射破坏单例");
}*/
}
}
private volatile static LazyMan lazyMan;
//双重检测锁模式的懒汉式单例,DCL模式
public static LazyMan getInstance() {
if(lazyMan == null) {
synchronized (LazyMan.class) {
if(lazyMan == null) {
lazyMan = new LazyMan();//不是原子性操作
/**
* 不是原子性操作有三步操作
* 1、分配内存空间
* 2、执行构造方法,初始化对象
* 3、把这个对象指向这个空间
*
* 可能发生执行重排
* 比如本来我们期望是 123
* 结果走成 132
*/
}
}
}
return lazyMan;
}
public static void main(String[] args) throws Exception {
/* for (int i = 0; i < 10; i++) {
new Thread(() -> {
LazyMan.getInstance();
}).start();
}*/
Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor();
constructor.setAccessible(true);
LazyMan lazyMan1 = constructor.newInstance(null);
//LazyMan lazyMan1 = LazyMan.getInstance();
LazyMan lazyMan2 = constructor.newInstance(null);
System.out.println(lazyMan1);
System.out.println(lazyMan2);
}
}
静态内部类
//静态内部类
public class Holder {
private Holder() {}
public static Holder getInstance() {
return InnerClass.HOLDER;
}
public static class InnerClass {
private static final Holder HOLDER = new Holder();
}
}
枚举类实现单例
public class User {
//私有化构造函数
private User(){ }
//定义一个静态枚举类
static enum SingletonEnum{
//创建一个枚举对象,该对象天生为单例
INSTANCE;
private User user;
//私有化枚举的构造函数
private SingletonEnum(){
user=new User();
}
public User getInstance(){
return user;
}
}
//对外暴露一个获取User对象的静态方法
public static User getInstance(){
return SingletonEnum.INSTANCE.getInstance();
}
}
class Test {
public static void main(String [] args){
System.out.println(User.getInstance());
System.out.println(User.getInstance());
System.out.println(User.getInstance()==User.getInstance());
}
}
Java实现单例模式的几种方法,每种方法各有优劣势,最为安全的个人觉得是枚举类实现单例模式,但是本人日常编码比较少接触到。目前能力有限,文章内容深度可能有限,请多见谅,多指教。
希望能帮助到大家。
最后希望大家有错请指点,本人为小白。在博客为了记录自己的学习历程。感谢!!!