Java并发编程之对象发布(Publish)和逸出(Escape)

什么是对象发布:

使一个对象能够被当前范围之外的代码所使用。

示例:

@Slf4j
public class UnsafePublish {

    private String[] states = {"a", "b", "c"};

    public String[] getStates() {
        return states;
    }

    public static void main(String[] args) {
        UnsafePublish unsafePublish = new UnsafePublish();
        log.info("{}", Arrays.toString(unsafePublish.getStates()));

        unsafePublish.getStates()[0] = "d";
        log.info("{}", Arrays.toString(unsafePublish.getStates()));
    }
}

通过public访问级别发布了类的域(states),在类的任何外部线程都可以访问这些域。这样的发布对象是不安全的,因为不知道其他线程是否会修改这个域。简单的说通过unsafePublish发布了这个类的实例。

 

什么是对象逸出:

一个错误的发布。当一个对象还没有构造完成时,就使它被其他线程所见。

示例:

@Slf4j
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();
    }
}

Escape类的构造方法还没有构造完成,它的内部类InnerClass就能得到该类的对象引用,称之为对象逸出。

再看另外一种逃逸:


public class Escape {
 
	private int id = 0;
	private String name = null;
 
	public Escape() {
		new Thread(new MyRun()).start();
		new Thread(new MyRun()).start();
		name = "zhangsan";
	}
 
	private class MyRun implements Runnable {
		@Override
		public void run() {
 
			System.out.println(Escape.this.name);
			System.out.println(Escape.this.id);
 
		}
	}
 
	public static void main(String[] args) {
		new Escape();
	}

在Escape构造方法中,原本是要初始化该类的属性name的值为zhangsan,但是因为在构造方法中,启动线程,可能没有执行到name="zhangsan",线程就已经执行了,导致线程中name的值为null值。

 

解决方法:

在构造函数执行完之前,要避免使用Object.this这种引用和避免在构造函数中启动线程。

 

安全发布的四种方式:

  1. 在静态初始化函数中初始化一个对象引用
  2. 将对象的引用保持到volitale类型域中或者AtomicReference对象中
  3. 将对象的引用保存到某个正确的构造对象的final类型域中
  4. 将对象的引用保持到一个由锁保护的域中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值