单例模式
八种创建方式
1、饿汉式
优点:
- 简单好理解,便于使用,推荐实际工作中使用
- 线程安全
缺点
-
不能实现lazy-loading(懒加载),
即不管用到与否,类装载时即完成初始化。 -
实现机制:将构造器私有化 即外部不可以调用构造方法构造新对象
-
所有获取该类对象的操作 只能通过getInstance方法来进行获取。
public class Singleton01HungryDemo {
private static final Singleton01HungryDemo instance = new Singleton01HungryDemo();
/**
* 构造方法私有化
*/
private Singleton01HungryDemo() {
}
/**
* 给外部提供获取实例的方法
* @return
*/
public static Singleton01HungryDemo getInstance() {
return instance;
}
}
2、静态代码块饿汉式
3、懒汉式
优点:
- 只有真正用到时候才进行加载
缺点:
- 线程不安全(不推荐使用,没有实用价值)
- 线程不安全的详解:如果多个线程同时进行到代码的21行即进行判断是否为null,同时均为null,即会执行实例化的代码无法保证单例,提供了简单的验证办法,即启动100个线程同时进行调用,判断hashcode是否相同
public class Singleton02LazyDemo01 {
private static Singleton02LazyDemo01 instance;
private Singleton02LazyDemo01() {
}
public static Singleton02LazyDemo01 getInstance() {
if (null == instance) {
//线程进行短暂休眠,不然很难看到效果
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton02LazyDemo01();
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() ->
System.out.println(Singleton02LazyDemo01.getInstance().hashCode())
).start();
}
}
}
4、加锁类型的懒汉式(sychornized锁方法实现)
优点:
- 在原有基础上保证了线程安全
缺点:
- 每次都要获取锁释放锁 效率低下(不推荐使用)
public class Singleton03LazyDemo02 {
private Singleton03LazyDemo02() {
}
private static Singleton03LazyDemo02 instance;
public static synchronized Singleton03LazyDemo02 getInstance(){
if(null == instance){
//线程进行短暂休眠,不然很难看到效果
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton03LazyDemo02();
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() ->
System.out.println(Singleton03LazyDemo02.getInstance().hashCode())
).start();
}
}
}
5、加锁代码块形式的懒汉式
- 试图通过加同步代码块来进行效率提升,但仍然线程不安全当判断等于null之后,虽然获取不到锁,但是,当获取到锁之后依然会执行new的操作,即不再是单例的
优点:
- 没有
缺点:
- 线程并不安全
public class Singleton04LazyDemo03 {
private Singleton04LazyDemo03() {
}
private static Singleton04LazyDemo03 instance;
public static Singleton04LazyDemo03 getInstance() {
if (null == instance){
synchronized (Singleton04LazyDemo03.class){
instance = new Singleton04LazyDemo03();
}
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() ->
System.out.println(Singleton04LazyDemo03.getInstance().hashCode())
).start();
}
}
}
6、双重检查机制的懒汉式
- 通过两次检测保证了线程安全,而且效率
相比直接加锁的形式效率要高很多,推荐
使用
public class Singleton05LazyDemo04DoubleCheck {
private Singleton05LazyDemo04DoubleCheck() {
}
//防止指令重排
private static volatile Singleton05LazyDemo04DoubleCheck instance;
public static Singleton05LazyDemo04DoubleCheck getInstance() {
if (null == instance) {
synchronized (Singleton05LazyDemo04DoubleCheck.class) {
if (null == instance) {
instance = new Singleton05LazyDemo04DoubleCheck();
}
}
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() ->
System.out.println(Singleton05LazyDemo04DoubleCheck.getInstance().hashCode())
).start();
}
}
}
7、静态内部类形式的实现
通过静态内部类的形式来实现单例
优点:
- 线程安全,实现了lazy-loading 推荐使用
public class Singleton06InnerClass {
private Singleton06InnerClass() {
}
private static class InnerClass {
private static final Singleton06InnerClass instance = new Singleton06InnerClass();
}
public static Singleton06InnerClass getInstance() {
return InnerClass.instance;
}
}
8、enum形式的实现
- 完美写法 不仅可以解决线程同步,还可以防止反序列化即可以防止暴力反射
public enum Singleton07Enum {
INSTANCE;
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() ->
System.out.println(Singleton07Enum.INSTANCE.hashCode())
).start();
}
}
}