发布对象:
使一个对象能够被当前范围之外的代码所使用(public),不安全代码如下所示。
package concurrency.example.publish; import concurrency.annotations.NotThreadSafe; import lombok.extern.slf4j.Slf4j; import java.util.Arrays; @NotThreadSafe @Slf4j public class UnsafePublish { private String[] state = {"a", "b", "c"}; public String[] getState() { return state; } public static void main(String[] args) { UnsafePublish unsafePublish = new UnsafePublish(); String[] state = unsafePublish.getState(); log.info("{}", Arrays.toString(state)); //直接对state进行修改,任何线程都可以,所以不安全 unsafePublish.getState()[0] = "d"; log.info("{}", Arrays.toString(state)); } }
对象溢出:
一种错误发布。当一个对象还没有构造完成时,就使它被其他线程所见。
package concurrency.example.publish; import concurrency.annotations.NotRecommend; import concurrency.annotations.NotThreadSafe; import lombok.extern.slf4j.Slf4j; @Slf4j @NotThreadSafe @NotRecommend public class Escape { private int thisCanBeEscape = 0; public Escape() { new InnerClass(); } private class InnerClass { public InnerClass() { log.info("{}", Escape.this.thisCanBeEscape); } } public static void main(String[] args) { new Escape(); } }
如何才能安全发布对象呢?
1.单例懒汉模式,双层检测机制加入volatile后,线程安全
代码如下:
package concurrency.example.singleton; import concurrency.annotations.ThreadSafe; /* *Created by William on 2018/4/29 0029 * 懒汉模式,单例模式,双层检测机制加入volatile后,线程安全 * 单例的实例在第一次使用的时候创建 */ @ThreadSafe public class SingletonExample5 { //私有的构造函数 private SingletonExample5() { } //单例对象,使用volatile禁止发生指令重排 private volatile static SingletonExample5 instance = null; //静态工厂方法获取单例对象 public static SingletonExample5 getInstance() { if (instance == null) { synchronized (SingletonExample5.class) {//采用双层检测机制 if (instance == null) { instance = new SingletonExample5(); } } } return instance; } }
2.单例饿汉模式
package concurrency.example.singleton; import concurrency.annotations.ThreadSafe; /* *Created by William on 2018/4/29 0029 * 饿汉模式,对比SingletonExample2,使用静态快进行初始化 */ @ThreadSafe public class SingletonExample6 { //私有的构造函数 private SingletonExample6() { } //单例对象 private static SingletonExample6 instance = null; static { instance = new SingletonExample6(); } //静态工厂方法获取单例对象 public static SingletonExample6 getInstance() { return instance; } public static void main(String[] args){ System.out.println(instance.hashCode()); System.out.println(instance.hashCode()); } }
3.最安全的,还是使用单例枚举模式,最推荐的模式,不浪费资源
package concurrency.example.singleton; import concurrency.annotations.Recommend; import concurrency.annotations.ThreadSafe; /* *Created by William on 2018/4/29 0029 * 枚举模式,最安全,最推荐的模式,不浪费资源 */ @ThreadSafe @Recommend public class SingletonExample7 { //私有的构造函数 private SingletonExample7() { } public static SingletonExample7 getInstance(){ return Singleton.INSTANCE.singleton; } private enum Singleton{ INSTANCE; private SingletonExample7 singleton; //JVM保证这个方法绝对只调用一次 Singleton(){ singleton = new SingletonExample7(); } public SingletonExample7 getSingleton() { return singleton; } } public static void main(String[] args){ System.out.println(SingletonExample7.getInstance().hashCode()); System.out.println(SingletonExample7.getInstance().hashCode()); } }