一 体系化深入学习并发编程由简入繁系统梳理并发知识点(14)


还有关于this赋值逸出的情况:
有这么一个User类:
class User{private int id;private String name;public User(int id, String name) throws InterruptedException {this.id = id;//在构造函数中对另一个类的user进行赋值ThisAssignmentEscape.user=this;Thread.sleep(100);this.name = name;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}}
public class ThisAssignmentEscape {static User user;public static void main(String[] args) throws InterruptedException {new Thread(()->{try {new User(1,"张三");} catch (InterruptedException e) {e.printStackTrace();}}).start();Thread.sleep(100);System.out.println(user);}}
由于休眠时间的不同,导致this赋值的不同;
比如主线程中休眠100ms是这个结果:
User{id=1, name='null'}
而休眠200ms,又是另一种结果:
User{id=1, name='张三'}
下面是注册监听器的一个演示,当我们没有显示使用this时,也会出现的对象逸出的情况
注册监听事件:
//观察者模式interface Event{}interface EventListener{void onEvent(Event event);}static class MySource{private EventListener listener;void registerListener(EventListener eventListener){this.listener=eventListener;}void eventCome(Event event){if (listener!=null){listener.onEvent(event);}else {System.out.println("初始化未完成");}}}
主类的成员变量和构造方法
int count;public RegisterListener(MySource source) {source.registerListener(new EventListener() {@Overridepublic void onEvent(Event event) {System.out.println("\n获得的count:"+count);}});//赋值前执行其他的任务for (int i = 0; i <1000; i++) {System.out.print(" ");}count=77;}
主线程执行
public static void main(String[] args) {MySource source = new MySource();new Thread(()->{try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}source.eventCome(new Event() {});}).start();RegisterListener registerListener = new RegisterListener(source);}
打印的结果:有三种情况
预料之类:初始化未完成,获得的count:77
预料之外:获得的count:0
虽然在构造函数内部,没有使用this显式赋值,但是出现了在count赋值前,通过匿名内部类的方法访问到外部类的count(默认值为0)的情况
构造函数中启动线程:
public NewThreadInConstructor() {new Thread(()->{cities=new HashMap<>();cities.put(1,"北京");cities.put(2,"上海");cities.put(3,"广州");}).start();}
同样是之前的情况,我们采用在构造函数中使用匿名线程进行赋值初始化 。
public static void main(String[] args) throws InterruptedException {NewThreadInConstructor threadInConstructor = new NewThreadInConstructor();Map cities = threadInConstructor.getCities();//TimeUnit.SECONDS.sleep(1);System.out.println(cities.get(1));}
但是如果不休眠一段时间,让构造函数中的线程完成初始化,就会导致空指针异常 。
解决对象逸出问题
前面提到的对象逸出的两种情况
方法返回一个对象还未完成初始化,就将对象传递给外界
第一种情况,我们可以采取传递副本的方式
之前我们使用的方法如下
这种方法会导致我们的逸出,我们并不希望该对象被修改,但是有时又需要展示该对象,那么就可以使用传回一个副本