设计模式(Design pattern) java开发者必修的一门课程,而设计模式总的来说有很多种,但是当你融汇贯通之后,并不需要去考虑具体的用哪种模式,因为设计会把创建型、行为型和结构型这些模式融合在一起。
首先讲一下单例模式,单例模式:根据名字就能想到只有一个实例,自己负责创建自己的对象,而这个类提供了一种访问其唯一对象的方式,不用实例化,可以直接访问,拿过来用。
单例模式我是把它分为四种:
1、饿汉模式
2、懒汉模式
3、静态内部类
4、枚举
1、饿汉模式
实例在初始化的时候就可以
存在(你在或不在,我都在那里,不离不弃),其实在开发中用这一种本人觉得就够了,浪费一点内存空间不会影响大局(话说你不用的,你装载它干啥)。
优点:线程安全
缺点:浪费内存空间
代码:
/**
* 饿汉式
* 类加载到内存后,就实例化一个单例,JVM保证线程安全
* 简单实用,推荐使用!
* 唯一缺点:不管用到与否,类装载时就完成实例化
*
*/
public class Mgr01{
private static final Mgr01 INSTANCE = new Mgr01();
private Mgr01() {};
public static Mgr01 getInstance() {
return INSTANCE;
}
}
2、懒汉模式
顾名思义,懒汉模式,我不用我就不去实例化,等用的时候我再实例化,懒汉模式可分为几种,下面我就一一介绍一下
(1)按需初始化,但是会带来线程不安全的问题,多个线程访问就会多次初始化(Thread.sleep(1)是为了测试多个线程)
代码:
/**
* lazy loading
* 也称懒汉式
* 虽然达到了按需初始化的目的,但却带来线程不安全的问题
*/
public class Mgr02 {
private static Mgr02 INSTANCE;
private Mgr02() {
}
public static Mgr02 getInstance() {
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr02();
}
return INSTANCE;
}
public void m() {
System.out.println("m");
}
}
(2)按需初始化,方法添加synchronized,这样效率会大大降低,因为每一次都会加锁,线程安全
代码:
/**
* lazy loading
* 也称懒汉式
* 可以通过synchronized解决,但也带来效率下降
*/
public class Mgr03 {
private static Mgr03 INSTANCE;
private Mgr03() {
}
public static synchronized Mgr03 getInstance() {
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr03();
}
return INSTANCE;
}
public void m() {
System.out.println("m");
}
}
(3)按需初始化,同步代码块,每次初始化的时候添加synchronized,线程不安全,因为可能多个线程进入判断之后
代码:
/**
* lazy loading
* 也称懒汉式
* 虽然达到了按需初始化的目的,但却带来线程不安全的问题
* 妄图通过减小同步代码块的方式提高效率,然后不可行
*/
public class Mgr04 {
private static Mgr04 INSTANCE;
private Mgr04() {
}
public static Mgr04 getInstance() {
if (INSTANCE == null) {
//妄图通过减小同步代码块的方式提高效率,然后不可行
synchronized (Mgr04.class) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr04();
}
}
return INSTANCE;
}
public void m() {
System.out.println("m");
}
}
(4)*双重检查 这个方式就是懒汉模式的最佳方式,里外全部判断,保证线程安全
代码:
/**
* lazy loading
* 也称懒汉式
* 双重检查
* volatile 也要添加,防止指令重排序(DCL单例是否要加volatile的问题)
*/
public class Mgr04 {
private static volatile Mgr04 INSTANCE; //JIT
private Mgr04() {
}
public static Mgr04 getInstance() {
if (INSTANCE == null) {
//双重检查
synchronized (Mgr04.class) {
if(INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr06();
}
}
}
return INSTANCE;
}
public void m() {
System.out.println("m");
}
}
3、静态内部类单例
加载外部类的时不会加载内部类,也可实现懒加载
优点:线程安全,代码部分不需要加锁,由JVM保证线程安全
缺点:可以被反序列化
代码:
/**
* 静态内部类方式
* JVM保证单例
* 加载外部类时不会加载内部类,这样可以实现懒加载
*/
public class Mgr05 {
private Mgr05() {
}
private static class Mgr05Holder {
private final static Mgr05 INSTANCE = new Mgr05();
}
public static Mgr05 getInstance() {
return Mgr05Holder.INSTANCE;
}
public void m() {
System.out.println("m");
}
}
4、枚举
优点:线程安全,防止反序列化
缺点:
代码:
/**
* 不仅可以解决线程同步,还可以防止反序列化。
*/
public enum Mgr06 {
INSTANCE;
public void m() {}
}
个人总结:这几种单例模式,个人建议使用饿汉式,因为我觉得浪费一点内存空间可以接收,如果是一个完美主义者可以用最后一个方式,这样不怕被破解。。。