1.饿汉式
package com.company.java_high_concurrency.chapter13;
//单例模式提供了一种在多线程情况下保证实例唯一性的解决方案
//我们从三个维度对其进行评估(线程安全、高性能、懒加载)
//饿汉式:可以保证多个线程下的唯一实例,getInstance()性能也比较高,但是无法进行懒加载
final public class Hungry{
//实例变量
private byte[] data = new byte[1024];
//在定义实例对象的时候直接初始化
private static Hungry instance = new Hungry();
//构造器私有,不允许外部new
private Hungry(){
}
public static Hungry getInstance(){
return instance;
}
}
2.懒汉式
package com.company.java_high_concurrency.chapter13;
//懒汉式:可以保证实例的懒加载,但是无法保证实例的唯一性
//在测试类调用方法的时候,判断instance为空,然后创建对象,单线程下时没有问题的,但是多线程下,可能导致实例化多次,并不能保证单例的唯一性
public class LazyBones {
//实例变量
private byte[] data = new byte[1024];
//定义实例,但是不直接初始化
private static LazyBones instance = null;
private LazyBones(){
}
public static LazyBones getInstance(){
if(null == instance){
instance = new LazyBones();
}
return instance;
}
}
3.懒汉式+同步方法
```java
package com.company.java_high_concurrency.chapter13;
//懒汉式+同步方法:既满足了懒加载,又保证了实例的唯一,但是synchronized关键字天生的排它性导致了getInstance()在同一时刻被一个线程所访问,效率低下
public final class HungryAndLazy {
//实例变量
private byte[] data = new byte[1024];
private static HungryAndLazy instance = null;
private HungryAndLazy(){
}
//向getInstance()中加入同步控制,每次只能有一个线程能够进入
public static synchronized HungryAndLazy getInstance(){
if (instance == null){
instance = new HungryAndLazy();
}
return instance;
}
}
4.Double-Check
package com.company.java_high_concurrency.chapter13;
import java.net.Socket;
import java.sql.Connection;
//Double-Check:双重校验模式
//既满足懒加载,又保证了instance实例的唯一性,还提供了高效的数据同步策略,可以允许多个线程同时对getInstance()的访问
// 但是这种方式在多线程的情况下有可能会引起————空指针异常
/**为什么会引发空指针异常?
* 假设有两个线程(线程1和线程2)
* 线程1 : instance == null 满足 -》获得锁 -》创建instance实例 -》创建conn -》创建socket实例
* 线程2 : 判断到install不为null,即可返回并且使用类的实例变量conn或者socket,但是不幸此时可能conn或者socket还未创建完成
*/
public class DoubleCheck {
//实例变量
private byte[] data = new byte[1024];
private static DoubleCheck instance = null;
Connection connection;
Socket socket;
DoubleCheck(){
// this.connection;
// this.socket;
}
public static DoubleCheck getInstance(){
//当instance为空时,进入同步代码块,同时该判断避免了每次都需要进入同步代码块,可以提高效益
if (null == instance){
//只有一个线程能获得DoubleCheck.class关联的monitor
synchronized (DoubleCheck.class){
//判断如果install为null则创建
if (null == instance){
instance = new DoubleCheck();
}
}
}
return instance;
}
}
5.Volatile+Double-Check
package com.company.java_high_concurrency.chapter13;
import java.net.Socket;
import java.sql.Connection;
//Volatile+Double+Check
//Double-Check虽然是一种巧妙的设计,但是可能引起类变量的实例化conn和socket发生在instance实例化之后,这一切均是jvm在运行时————指令重排序————所导致的
//而volatile关键字2则可以防止这种重排序的发生,因此代码稍微做修改既可以满足多线程下的单例,懒加载以及获取实例的高效性
public class VolatileDoubleCheck {
//实例变量
private byte[] data = new byte[1024];
private volatile static DoubleCheck instance = null;
Connection connection;
Socket socket;
VolatileDoubleCheck(){
// this.connection;
// this.socket;
}
public static DoubleCheck getInstance(){
//当instance为空时,进入同步代码块,同时该判断避免了每次都需要进入同步代码块,可以提高效益
if (null == instance){
//只有一个线程能获得DoubleCheck.class关联的monitor
synchronized (DoubleCheck.class){
//判断如果install为null则创建
if (null == instance){
instance = new DoubleCheck();
}
}
}
return instance;
}
}
6.Holder
package com.company.java_high_concurrency.chapter13;
//Holder:完全借助了类加载的特点
//在Holder中并没有instance的静态成员,而是放在静态内部类Holder1之中,因此在Holder类的初始化过程并不会创建Holder的实例,
//Holder1类中定义了Holder的静态变量,并且直接进行了实例化,当Holder被主动引用的时候则会创建Holder的实例
/**
* Holder实例的创建过程在JAVA程序编译时期收集到<clinit>()方法中,该方法又是同步方法,既可以保证内存的可见性,jvm指令的顺序性和原子性
* Holder方式的单例模式设计是最好的设计之一,也是目前使用比较广的设计之一
*/
public final class Holder {
//实例变量
private byte[] data = new byte[1024];
private Holder(){
}
//在静态内部类中持有Holder实例,并且可以直接被初始化
private static class Holder1{
private static Holder instance = new Holder();
}
//调用getInstance(),事实上是获得Holder的instance静态属性
public static Holder getInstance(){
return Holder1.instance;
}
}
7.枚举
package com.company.java_high_concurrency.chapter13;
//枚举:枚举类型不允许被继承,同样是线程安全的且只能被实例化一次,但是枚举类型不能够懒加载
public enum Enum {
INSTANCE;
//实例变量
private byte[] data = new byte[1024];
Enum(){
System.out.println("INSTANCE will be initialized immediately");
}
public static void method(){
//调用该方法则会使用Enum,INSTANCE将会被实例化
}
public static Enum getInstance(){
return INSTANCE;
}
public static void main(String[] args) {
//1.
Enum.getInstance();
//2.
Enum.method();
}
}
//但是也可以对其进行改造,增加懒加载的特性,类似Holder的方式
枚举+懒加载
package com.company.java_high_concurrency.chapter13;
public class EnumHolderTest {
//实例类型
private byte[] data = new byte[1024];
private EnumHolderTest(){
}
//使用枚举充当holder
private enum EnumHolder{
INSTANCE;
private EnumHolderTest instance;
EnumHolder(){
this.instance = new EnumHolderTest();
}
private EnumHolderTest getEnumHolderTest(){
return instance;
}
}
public static EnumHolderTest getInstance(){
return EnumHolder.INSTANCE.getEnumHolderTest();
}
}