JAVA concurrency学习笔记之"发布" 与 "溢出"
-------------------------------------------------------------------------------------------------------------------------------------------
今晚闲来无事决定看看拿去了很久没看的java并发编程,刚好看到了一个自己不知道的东西,于是兴致所致,决定写一篇博客记录下
进入正题: 什么是发布(Publish)呢?在java并发编程实战这本书里面是这样定义的:"发布"一个对象的意思是指,使对象能够在当前作用域以外的代码中使用。
书中还具体说了三种发布行为:
- 将一个指向该对象的引用保存到其他代码可以访问的地方
- 在某一个非私有的方法中返回该引用
- 将引用传递到其他类的方法中
- 发布一个内部的类实例(这种稍微复杂点)
下面我们一起来看一下这几种情况都是怎么溢出的,并且产生线程问题
首先来看下第一种
package com.example.demo.publishAndEscape;
import java.util.HashSet;
import java.util.Set;
public class PublishObject {
public static Set<String> numbers;
public void initialize() {
numbers = new HashSet<>();
System.out.println("numbers object hashcode is " + numbers.getClass().hashCode());
}
}
测试代码
package com.example.demo;
import com.example.demo.publishAndEscape.PublishObject;
public class DemoApplication {
public static void main(String[] args) {
PublishObject object = new PublishObject();
for (int i = 0; i < 50; i++) {
Thread t1= new Thread(() -> {
object.initialize();
System.out.println("object hashcode is " + PublishObject.numbers.getClass().hashCode());
PublishObject.numbers.add("aaaa");
});
Thread t2= new Thread(() -> {
System.out.println(PublishObject.numbers.contains("aaaa"));
});
t1.start();
t2.start();
}
}
}
结果
果然 溢出的对象始终是那一个,有可能这个例子不是很好,大家包容吧
接下来我们看看非私有方法返回的问题
package com.example.demo.publishAndEscape;
public class UnsafeStates {
private String[] sates = new String[] {"AK","AL","AE"};
public String[] getSates() {
System.out.println(Thread.currentThread().getName()+":innner,state item object hashcode is" + sates[1].hashCode() + sates[1]);
return sates;
}
}
测试一:
package com.example.demo;
import com.example.demo.publishAndEscape.UnsafeStates;
public class DemoApplication {
public static void main(String[] args) {
Object obj = new Object();
Thread t1= new Thread(() -> {
UnsafeStates states = new UnsafeStates();
System.out.println("change after,state item object hashcode is" + states.getSates()[1].hashCode() +
states.getSates()[1]);
});
Thread t2= new Thread(() -> {
UnsafeStates states = new UnsafeStates();
System.out.println("change after,state item object hashcode is" + states.getSates()[1].hashCode() +
states.getSates()[1]);
});
t1.start();
t2.start();
}
}
结果:
结果发现不管是在类的内部还是外部我们始终操作的是一个类,现在我们把测试代码该一下就能发现线程问题了
package com.example.demo;
import com.example.demo.publishAndEscape.UnsafeStates;
public class DemoApplication {
public static void main(String[] args) {
Object obj = new Object();
Thread t1= new Thread(() -> {
UnsafeStates states = new UnsafeStates();
states.getSates()[1]="a";
System.out.println("change after,state item object hashcode is" + states.getSates()[1].hashCode() +
states.getSates()[1]);
});
Thread t2= new Thread(() -> {
UnsafeStates states = new UnsafeStates();
System.out.println("change after,state item object hashcode is" + states.getSates()[1].hashCode() +
states.getSates()[1]);
});
t1.start();
t2.start();
}
}
最后在看一种内部类的实例,这个比较隐式,不容易看出来
package com.example.demo.publishAndEscape;
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registListener(new EventListener() {
@Override
public void onEvent(Event e) {
System.out.println("event publish "+e.getName());
}
});
}
}
测试类
package com.example.demo;
import com.example.demo.publishAndEscape.Event;
import com.example.demo.publishAndEscape.EventListener;
import com.example.demo.publishAndEscape.EventSource;
import com.example.demo.publishAndEscape.ThisEscape;
public class DemoApplication {
public static void main(String[] args) {
EventSource eventSource = new EventSource() {
@Override
public void registListener(EventListener listener) {
listener.onEvent(new Event("sleep"));
}
};
ThisEscape escape = new ThisEscape(eventSource);
}
}
结果
从结果我们可以看出,虽然只是注册了个listener,却隐式的也把ThisEscape个发布出去了,溢出了
这便是发布与溢出,个人学习理解,学习理解能力有限,如有错误欢迎大佬指出,我们一起进步