package com.geely.design.pattern.creational.singleton;
import java.io.Serializable;
/**
* Created by geely
*/
public class HungrySingleton implements Serializable,Cloneable{
private final static HungrySingleton hungrySingleton;
static{
hungrySingleton = new HungrySingleton();
}
private HungrySingleton(){
if(hungrySingleton != null){
throw new RuntimeException("单例构造器禁止反射调用");
}
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
private Object readResolve(){
return hungrySingleton;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return getInstance();
}
}
package com.geely.design.pattern.creational.singleton;
/**
* Created by geely
*/
public class LazyDoubleCheckSingleton {
private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
private LazyDoubleCheckSingleton(){
}
public static LazyDoubleCheckSingleton getInstance(){
if(lazyDoubleCheckSingleton == null){
synchronized (LazyDoubleCheckSingleton.class){
if(lazyDoubleCheckSingleton == null){
lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
//1.分配内存给这个对象
// //3.设置lazyDoubleCheckSingleton 指向刚分配的内存地址
//2.初始化对象
// intra-thread semantics
// ---------------//3.设置lazyDoubleCheckSingleton 指向刚分配的内存地址
}
}
}
return lazyDoubleCheckSingleton;
}
}
package com.geely.design.pattern.creational.singleton;
/**
* Created by geely
*/
public class LazySingleton {
private static LazySingleton lazySingleton = null;
private LazySingleton(){
if(lazySingleton != null){
throw new RuntimeException("单例构造器禁止反射调用");
}
}
public synchronized static LazySingleton getInstance(){
if(lazySingleton == null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
// public static void main(String[] args) throws NoSuchMethodException,
// IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
// Class objectClass = LazySingleton.class;
// Constructor c = objectClass.getDeclaredConstructor();
// c.setAccessible(true);
//
// LazySingleton o1 = LazySingleton.getInstance();
//
// Field flag = o1.getClass().getDeclaredField("flag");
// flag.setAccessible(true);
// flag.set(o1,true);
//
//
// LazySingleton o2 = (LazySingleton) c.newInstance();
//
// System.out.println(o1);
// System.out.println(o2);
// System.out.println(o1==o2);
// }
}
package com.geely.design.pattern.creational.singleton;
/**
* Created by geely
*/
public class StaticInnerClassSingleton {
private static class InnerClass{
private static StaticInnerClassSingleton staticInnerClassSingleton =
new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance(){
return InnerClass.staticInnerClassSingleton;
}
private StaticInnerClassSingleton(){
if(InnerClass.staticInnerClassSingleton != null){
throw new RuntimeException("单例构造器禁止反射调用");
}
}
}
package designPattern;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException, CloneNotSupportedException,
IOException, ClassNotFoundException {
Class clazz = StaticInnerClassSignletonLazy.class;
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
StaticInnerClassSignletonLazy newInstance =
(StaticInnerClassSignletonLazy)constructor.newInstance();
StaticInnerClassSignletonLazy instance = StaticInnerClassSignletonLazy.getSignleton();
System.out.println(instance == newInstance);
StaticInnerClassSignletonLazy instance = StaticInnerClassSignletonLazy.getSignleton();
StaticInnerClassSignletonLazy newInstance = (StaticInnerClassSignletonLazy)instance.clone();
System.out.println(instance == newInstance);
StaticInnerClassSignletonLazy instance = StaticInnerClassSignletonLazy.getSignleton();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("132"));
oos.writeObject(instance);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("132"));
StaticInnerClassSignletonLazy newInstance = (StaticInnerClassSignletonLazy)ois.readObject();
System.out.println(newInstance == instance);
}
}
背景:我们在实现单例模式的时候往往会忽略掉多线程的情况,就是写的代码在单线程的情况下是没问题的,但是一碰到多个线程的时候,由于代码没写好,就会引发很多问题,而且这些问题都是很隐蔽和很难排查的。
例子1:没有volatile修饰的uniqueInstance
public class Singleton {
private static Singleton uniqueInstance;
private Singleton(){
}
public static Singleton getInstance(){
if(uniqueInstance == null){ //#1
synchronized(Singleton.class){ //#2
if(uniqueInstance == null){ //#3
uniqueInstance = new Singleton(); //#4
System.out.println(Thread.currentThread().getName() + ": uniqueInstance is initalized..."); //#5.1
} else {
System.out.println(Thread.currentThread().getName() + ": uniqueInstance is not null now..."); //#5.2
}
}
}
return uniqueInstance;
}
}
1 public class TestSingleton {
2 public static void main(final String[] args) throws InterruptedException {
3 for (int i = 1; i <= 100000; i++) {
4 final Thread t1 = new Thread(new ThreadSingleton());
5 t1.setName("thread" + i);
6 t1.start();
7 }
8 }
9
10 public static class ThreadSingleton implements Runnable {
11 @Override
12 public void run() {
13 Singleton.getInstance();
14 }
15 }
16 }
这里面的结果有可能会是:(没有真正重现过,太难模拟了)
1 thread2: uniqueInstance is initalized...
2 thread3: uniqueInstance is initalized...
Singleton被实例化两次了,和我们的单例模式设计期望值不一致:类永远只被实例化一次.
原因分析:
1. thread2进入#1, 这时子线程的uniqueInstance都是为空的,thread2让出CPU资源给thread3
2. thread3进入#1, 这时子线程的uniqueInstance都是为空的, thread3让出CPO资源给thread2
3. thread2会依次执行#2,#3,#4, #5.1,最终在thread2里面实例化了uniqueInstance。thread2执行完毕让出CPO资源给thread3
4. thread3接着#1跑下去,跑到#3的时候,由于#1里面拿到的uniqueInstance还是空(并没有及时从thread2里面拿到最新的),所以thread3仍然会执行#4,#5.1
5. 最后在thread2和thread3都实例化了uniqueInstance
例子2:用volatile修饰的uniqueInstance
这里就不贴重复的代码了,因为只是加多一个volatile来修饰成员变量:uniqueInstance,
但是结果却是正确的了, 其中一个可能结果:
thread2: uniqueInstance is initalized
thread3: uniqueInstance is not null now...
原因分析:
volatile(java5):可以保证多线程下的可见性;
读volatile:每当子线程某一语句要用到volatile变量时,都会从主线程重新拷贝一份,这样就保证子线程的会跟主线程的一致。
写volatile: 每当子线程某一语句要写volatile变量时,都会在读完后同步到主线程去,这样就保证主线程的变量及时更新。
1. thread2进入#1, 这时子线程的uniqueInstance都是为空的(java内存模型会从主线程拷贝一份uniqueInstance=null到子线程thread2),thread2让出CPU资源给thread3 2. thread3进入#1, 这时子线程的uniqueInstance都是为空的(java内存模型会从主线程拷贝一份uniqueInstance=null到子线程thread2), thread3让出CPO资源给thread2 3. thread2会依次执行#2,#3,#4, #5.1,最终在thread2里面实例化了uniqueInstance(由于是volatile修饰的变量,会马上同步到主线程的变量去)。thread2执行完毕让出CPU资源给thread3 4. thread3接着#1跑下去,跑到#3的时候,会又一次从主线程拷贝一份uniqueInstance!=null回来,所以thread3就直接跑到了#5.2 5. 最后在thread3不再会重复实例化uniqueInstance了
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。