发布对象:
使一个对象能够被当前范围之外的代码所使用(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());
}
}