java并发编程(二)对象的共享
来源:互联网 发布:电子琴教学软件 编辑:程序博客网 时间:2024/05/16 15:02
接昨天 《java并发编程(一)线程安全性》
发布和逸出:
“publish”,发布一个对象的意思是:使对象能够在当前作用域之外的代码中使用。(Publishingan object means making it available to code outside of its current scope )。发布内部状态可能破坏封装性,并使得程序难以维系不变性条件。如果对象在构造完成前就发布该对象,就会破坏线程安全性。当某个不应该发布的对象被发布时,被称为“逸出”。
public static Set<Secret> know;public void init() {know = new HashSet<>();}当发布某个对象时,可能会间接的发布其他对象。如果将一个Secret对象添加到集合know中,那么同样会发布这个对象,因为任何代码都可以便利这个集合,并获得对这个心Secret对象的引用。同样从非私有方法返回一个引用,那么同样会发布返回的对象。
private String[] states = new String[] { "AK", "AL" };public String[] getState() {return states;}代码发布了一个本是私有的状态数组,逸出了他所在的作用域,任何一个调用着都能修改这个数组的内容。封装的主要原因是:封装能够对程序的正确性进行分析,并使无意破坏设计约束条件能难。(it makesit practical to analyze programs for correctness and harder to violate design con-straints accidentally. )
还有一种发布对象或其内部状态的机制就是发布一个内部的类实例。看例子
</pre><div><span style="white-space: pre;"></span><pre name="code" class="java">public class ThisEscape {private String name = null;public ThisEscape(EventSource eventSource) {eventSource.registerListener(new EventListener() {@Overridepublic void onEvent() {System.out.println(name.toString());}});name = "23";}}
如果想在构造函数中注册一个事件监听或者启动线程,可以使用一个私有的构造函数,和一个公共的工厂方法。
看书中的例子:
public class SafeListener {private final EventListener eventListener;<span style="color:#ff0000">private</span> SafeListener(EventSource eventSource) {eventListener = new EventListener() {@Overridepublic void onEvent() {}};}public static SafeListener newInstance(EventSource eventSource) {SafeListener listener = new SafeListener(eventSource);eventSource.registerListener(listener.eventListener);return listener;}}看到newInstance 突然想想到两点 :
1.以前做过一个android 项目,引入的一个第三方框架,好像也是这样写的,当时只知道用,不懂为什么。有时间一定补上
2.newInstance 让我想起了 反射 ,赶紧翻看了下Class 源码,并分析。
<span style="color:#ff0000">private</span> Class() {}同样,不让自己创建对象,并且带有说明
/*
* Constructor. Only the Java Virtual Machine creates Class
* objects.
*/
只有虚拟机才能创建Class对象,Class 类中static方法不是很多,我们要得到一个字节码只能通过Class.forName,这是不是也是为了防止逸出呢? 请大牛指教。public static Class<?> forName(String className) throws ClassNotFoundException { return forName0(className, true, ClassLoader.getClassLoader(Reflection.getCallerClass())); }
线程封闭
栈封闭
ThreadLocal类
ThreadLocal类保存的是 线程的标示和要保存的值。查看ThreadLocal源码就能明白原理。
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
set方法首先得到当前线程,然后通过传入的对象,取得Map集合,如果map为空就创建,不为空就更新。
同样的 get方法 我们也大约能猜到是什么样的,请看
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
在现实应用程序框架大量的运用了ThreadLocal ,我觉得浏览器在访问服务器时候就可以通过 ThreadLocal来区分客户端。因为 只要浏览器访问服务器 就会开启一个线程。
不可变性:
当一个对象不可变,那他一定是线程安全的。
不可变对象必须包括三点:
1.对象创建后其状态就不能改变。
2.对象的所有域都是fnal类型。
3.对象是正确的创建的。(在对象创建时期,this引用没有逸出)
final关键字修饰的变量 引用不可变,但是对象依然可以被修改。java中,final域能保证初始化过程的安全性。
一个编程的习惯:除非需要更高的可见性,否则应将所有的域都声明为私有域,除非某个域是可见的,否则将他声明为final域。
安全性发布的常用模式:
可变对象必须通过安全方式来发布,这就意味着发布和使用该对象的线程时都必须同步。要安全地发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见。以下方式可以保证安全的发布:
1.在静态初始化函数中初始化一个对象的引用。
2.将对象的引用保存到volatile类型的域活着AtomicReference对象中。
3.将对象的引用保存到某个正确构造对象的final类型域中。
4.将对象的引用保存到一个由锁保护的域中。
0 0
- Java 并发编程之对象的共享(二)
- java并发编程(二)对象的共享
- Java并发编程实战笔记(二):对象的共享
- JAVA并发编程(二)内置锁和对象共享
- Java 并发编程(二)——对象共享
- Java 并发编程之对象的共享
- java并发编程实战-对象的共享
- [Java并发编程实战] 对象的共享
- java并发编程实战-对象的共享
- java并发编程读书笔记(1)-- 对象的共享
- Java并发编程实战(学习笔记二 第三章 对象的共享 上)
- Java并发编程实战(学习笔记二 第三章 对象的共享 下 线程封闭)
- Java 并发编程(二)对象的可见性
- 并发编程实战学习笔记(二)——对象的共享
- java并发编程 第三节 对象的共享
- 《Java并发编程实战》第三章 对象的共享 读书笔记
- 《Java并发编程实战》---线程安全性---对象的共享
- java并发编程基础之对象的共享
- 新组织,新动态——CSDN俱乐部举办“微软创新杯”宣讲会
- Android Button基础
- 蓝牙音箱方案选用及设计注意
- Android属性(property)机制
- 代码规范中常见问题举例说明
- java并发编程(二)对象的共享
- Handler
- codevs3027 线段覆盖2(DP)
- cin的错误标记和缓冲区清空
- 【畅言】创业CEO分享:入行4年,浅谈TMT产业的危机和应对
- android问题
- 五个常用MySQL图形化管理工具
- 硬盘改抛光机,顺便了解硬盘构造
- Name That Number (namenum)