单例模式
Java实现
饿汉式、线程安全、最简单的方式
/**
* 静态变量实现方式、线程安全、饿汉式; 是最常用的一种方式
*
* @author yangsx
* @version 1.0
* @date 2019/9/11
*/
public class S1_HungerImplement {
private static final S1_HungerImplement INSTANCE = new S1_HungerImplement();
/* static {
INSTANCE = new S1_StaticFieldImplements();
}*/
private S1_HungerImplement() {
}
public static S1_HungerImplement getInstance() {
return INSTANCE;
}
}
懒汉式、非线程安全、最简单的方式
/**
* 懒汉式,线程不安全
*
* @author yangsx
* @version 1.0
* @date 2019/9/11
*/
public class S2_LazyLoadingImplement {
private static S2_LazyLoadingImplement INSTANCE;
private S2_LazyLoadingImplement() {
}
public static S2_LazyLoadingImplement getInstance() {
if (INSTANCE == null) {
INSTANCE = new S2_LazyLoadingImplement();
}
return INSTANCE;
}
}
懒汉式、线程安全、同步方法
/**
* 懒汉式、线程安全
*
* @author yangsx
* @version 1.0
* @date 2019/9/11
*/
public class S3_LazyThreadSafeImplement {
private static S3_LazyThreadSafeImplement INSTANCE;
private S3_LazyThreadSafeImplement() {
}
public static synchronized S3_LazyThreadSafeImplement getInstance() {
if (INSTANCE == null) {
INSTANCE = new S3_LazyThreadSafeImplement();
}
return INSTANCE;
}
}
懒汉式、线程安全、双重检查锁
同步方法的线程安全模式,缺点很明显,因为对象的创建之前,可能会做很多耗时操作,所以优化如下:
/**
* 懒汉式、线程安全, 减少了同步代码快的区域
* 此模式有问题,当多线程并发访问有问题,因为判断与初始化不是一个原子操作,有可能初始化多次
*
* @author yangsx
* @version 1.0
* @date 2019/9/11
*/
public class S4_LazyThreadSafeImplement2 {
private static S4_LazyThreadSafeImplement2 INSTANCE;
private S4_LazyThreadSafeImplement2() {
}
public static S4_LazyThreadSafeImplement2 getInstance() {
if (INSTANCE == null) {
synchronized (S4_LazyThreadSafeImplement2.class) {
INSTANCE = new S4_LazyThreadSafeImplement2();
}
}
return INSTANCE;
}
}
但是这种方式,是一种错误的实现方式,因为判断与初始化不是一个原子操作,有可能初始化多次。所以,使用双重检查锁替换该方式:
/**
* 懒汉式、线程安全, 双重检查锁方式
* 为了解决S4的问题,我们可以在synchronized内部再判断一次, 既缩小了同步区域,又保证了不会被初始化多次
* volatile用于禁止指令重排序
*
* @author yangsx
* @version 1.0
* @date 2019/9/11
*/
public class S5_DoubleCheckLockImplement {
private static volatile S5_DoubleCheckLockImplement INSTANCE;
private S5_DoubleCheckLockImplement() {
}
public static S5_DoubleCheckLockImplement getInstance() {
if (INSTANCE == null) {
synchronized(S5_DoubleCheckLockImplement.class) {
if (INSTANCE == null) {
INSTANCE = new S5_DoubleCheckLockImplement();
}
}
}
return INSTANCE;
}
}
懒汉式、静态内部类
/**
* 静态内部类方式,懒汉式,线程安全
*
* @author yangsx
* @version 1.0
* @date 2019/9/11
*/
public class S6_StaticInnerClassImplement {
private S6_StaticInnerClassImplement() {
}
private interface InstanceHolder {
S6_StaticInnerClassImplement INSTANCE = new S6_StaticInnerClassImplement();
}
// 当调用了getInstance方法时,类加载器才会去加载InstanceHolder类,从而才会初始化成员 INSTANCE
public static S6_StaticInnerClassImplement getInstance() {
return InstanceHolder.INSTANCE;
}
}
懒汉式、Enum实现、比较完美
/**
* 最完美的方式
* 枚举实现,饿汉式,线程安全. 可防止反序列化(因为枚举类没有构造方法)
*
* @author yangsx
* @version 1.0
* @date 2019/9/11
*/
public enum S7_EnumImplement {
INSTANCE;
@Override
public String toString() {
return getDeclaringClass().getCanonicalName() + "@" + hashCode();
}
}
饿汉式、容器单例
/**
* 容器单例, 比如spring容器
*
* @author yangsx
* @version 1.0
* @date 2019/9/11
*/
public class S8_ContainerImplement {
private static List<S8_ContainerImplement> set = new ArrayList<>();
static {
set.add(new S8_ContainerImplement());
}
public static S8_ContainerImplement getInstance() {
return set.get(0);
}
}
Golang实现
饿汉式、并发安全
type singleton struct{}
var ins *singleton = &singleton{}
func GetIns() *singleton{
return ins
}
懒汉式、并发不安全
type singleton struct{}
var ins *singleton
func GetIns() *singleton{
if ins == nil {
ins = &singleton{}
}
return ins
}
懒汉式、并发安全、加锁
type singleton struct{}
var ins *singleton
var mu sync.Mutex
func GetIns() *singleton{
mu.Lock()
defer mu.Unlock()
if ins == nil {
ins = &singleton{}
}
return ins
}
懒汉式、并发安全、双重检查锁
type singleton struct{}
var ins *singleton
var mu sync.Mutex
func GetIns() *singleton{
if ins == nil {
mu.Lock()
defer mu.Unlock()
if ins == nil {
ins = &singleton{}
}
}
return ins
}
懒汉式、并发安全、sync.Once
type singleton struct{}
var ins *singleton
var once sync.Once
func GetIns() *singleton {
once.Do(func(){
ins = &singleton{}
})
return ins
}
JDK中的单例模式
java.lang.Runtime#getRuntime()
,饿汉式、线程安全、最简单的方式java.awt.Desktop#getDesktop()
,懒汉式、线程安全、同步方法java.lang.System#getSecurityManager()
MyBatis ErrorContext
ErrorContext类用于记录本次执行过程中相关上下文信息,待发生Error时候其他组件就可以从本类实例中获取到相关的上下文信息。因为使用了ThreadLocal<T>
, 我们就能直接取到之前执行本SQL的线程上的信息, 也就很方便的构建出异常发生时的上下文,快速排错
public class ErrorContext {
private static final String LINE_SEPARATOR = System.lineSeparator();
// 将实例放入到线程本地变量中,饿汉
private static final ThreadLocal<ErrorContext> LOCAL = ThreadLocal.withInitial(ErrorContext::new);
private ErrorContext stored;
private String resource;
private String activity;
private String object;
private String message;
private String sql;
private Throwable cause;
// 构造函数私有化
private ErrorContext() {
}
// 获取实例,也就是错误信息上下文
public static ErrorContext instance() {
return LOCAL.get();
}
public ErrorContext store() {
ErrorContext newContext = new ErrorContext();
newContext.stored = this;
LOCAL.set(newContext);
return LOCAL.get();
}
public ErrorContext recall() {
if (stored != null) {
LOCAL.set(stored);
stored = null;
}
return LOCAL.get();
}
public ErrorContext resource(String resource) {
this.resource = resource;
return this;
}
public ErrorContext activity(String activity) {
this.activity = activity;
return this;
}
public ErrorContext object(String object) {
this.object = object;
return this;
}
public ErrorContext message(String message) {
this.message = message;
return this;
}
public ErrorContext sql(String sql) {
this.sql = sql;
return this;
}
public ErrorContext cause(Throwable cause) {
this.cause = cause;
return this;
}
// thread-local在使用后,需要清空,mybatis通过try-catch-finally的机制(针对sql语句),在finally块中调用此方法清空thread-local
public ErrorContext reset() {
resource = null;
activity = null;
object = null;
message = null;
sql = null;
cause = null;
LOCAL.remove();
return this;
}
@Override
public String toString() {
StringBuilder description = new StringBuilder();
// message
if (this.message != null) {
description.append(LINE_SEPARATOR);
description.append("### ");
description.append(this.message);
}
// resource
if (resource != null) {
description.append(LINE_SEPARATOR);
description.append("### The error may exist in ");
description.append(resource);
}
// object
if (object != null) {
description.append(LINE_SEPARATOR);
description.append("### The error may involve ");
description.append(object);
}
// activity
if (activity != null) {
description.append(LINE_SEPARATOR);
description.append("### The error occurred while ");
description.append(activity);
}
// sql
if (sql != null) {
description.append(LINE_SEPARATOR);
description.append("### SQL: ");
description.append(sql.replace('\n', ' ').replace('\r', ' ').replace('\t', ' ').trim());
}
// cause
if (cause != null) {
description.append(LINE_SEPARATOR);
description.append("### Cause: ");
description.append(cause.toString());
}
return description.toString();
}
}
最后更新于
这有帮助吗?