首页 > 编程语言 > 详细

java并发编程实战-第3章-对象的共享

时间:2015-09-15 02:05:52      阅读:145      评论:0      收藏:0      [点我收藏+]

java并发编程实战-第3章-对象的共享

如何共享和发布对象,使其能符合第2章所讨论的多个线程下的安全性访问。2-3章是第4章构建线程安全类

?

和通过java.util.concurrent类库来构建并发应用程序的重要基础

?

同步除了实现原子性操作外,另一个重要方面内存可见性

?

?

3.1可见性

?

? In order to ensure visibility of memory writes across threads, you must use synchronization.

?

? public class NoVisibility {

? ? private static boolean ready;

? ? private static int number;

?

? ? private static class ReaderThread extends Thread {

? ? ? ? public void run() {

? ? ? ? ? ? while (!ready)

? ? ? ? ? ? ? ? Thread.yield();

? ? ? ? ? ? System.out.println(number);

? ? ? ? }

? ? }

?

? ? public static void main(String[] args) {

? ? ? ? new ReaderThread().start();

? ? ? ? number = 42;

? ? ? ? ready = true;

? ? }

}

?

?

在没有同步的情况下,无法保证主线程写入的值对读线程是可见的(虽然如上代码测试几次可能都会输出42

?

?

在没有同步的情况下,编译器、处理器以及运行时都可能对执行顺序做调整(重排序)

?

3.1.1 失效数据

?

NoVisibility 可能产生失效数据,可能输出错误的结果、可能引起死循环、意料外的异常、被破坏的数据

?

结构等等

?

3.1.2 非原子的64位操作

?

? ?对于64位的long、double操作。jvm 允许拆分成2个32位的操作。所以在多个线程的读写下即使不考虑数

?

据失效、也是不安全的。除非使用volatile声明或者用锁保护

? ?

3.1.3 加锁与可见性

? ? ? ? ? Locking is not just about mutual exclusion; it is also about memory visibility

?

3.1.4 volatile

? ? ? When a field is declared volatile, the compiler and runtime are put on notice that this?

?

variable is shared and that operations on it should not be reordered with other memory?

?

operations.

? ? ? Volatile variables are not cached in registers or in caches where they are hidden from?

?

other processors, so a read of a volatile variable always returns the most recent write by any?

?

thread

?

? ? 即:1、不重排序 2、不缓存在寄存器或其他处理器不可见的地方

? ??

? ??

? ? volatile只能保证可见性,但不保证++count 的原子性。(原子变量提供了读-写-改的原子操作,通常

?

是一种更好的volatile变量)

?

? ?You can use volatile variables only when all the following criteria are met:(使用volatiel

?

,以下3个条件都要买足)

?

Writes to the variable do not depend on its current value, or you can?

?

ensure that only a single thread ever updates the value;

?

The variable does not participate in invariants with other state?

?

variables; and

?

Locking is not required for any other reason while the variable is?

?

being accessed.

? ??

? ??

? ? 适用场景:

? ? ?1、作为状态标志

? ? ?volatile boolean asleep;

? ? ? ...

? ? while (!asleep)

? ? ? ? countSomeSheep();

? ? ? ??

3.2 发布和逸出

? ? 发布:使对象在当前代码之外仍旧可用。比如存储对象的应用使其可以别的代码可以访问、通过非私有

?

方法返回、将引用传递给其他类的方法

? ? 逸出:An object that is published when it should not have been is said to have escaped.

? ??

? ? 逸出例子:

? ? 例子1:共有静态的变量

? ?Listing 3.5. Publishing an Object.

public static Set<Secret> knownSecrets;

?

public void initialize() {

? ?knownSecrets = new HashSet<Secret>();

}

?

? ? 如上共有静态的变量 knownSecrets,就是在没有initialize()完成,其它线程也能访问

? ??

? ? 例子2:使内部的可变状态逸出

? ? class UnsafeStates {

? ? private String[] states = new String[] {

? ? ? ? "AK", "AL" ...

? ? };

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

? ? }

? ?

? ??

? ? 例子3:在public构造函数中发布内部类(发布的EventListener含有ThisEscape的this的隐式引用,但

?

ThisEscape确没有构造完成)

? ? public class ThisEscape {

? ? public ThisEscape(EventSource source) {

? ? ? ? source.registerListener(

? ? ? ? ? ? new EventListener() {

? ? ? ? ? ? ? ? public void onEvent(Event e) {

? ? ? ? ? ? ? ? ? ? doSomething(e);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? });

? ? ?}

? ?}

? ?

? ?需要当且仅当构造函数返回时,对象才处于可预测的和一致性状态

? ?所以,可以如下正确的发布:

? ?使用工厂方法防止this引用在构造过程中逸出

? ?

? public class SafeListener {

? ?private final EventListener listener;

?

? ?private SafeListener() {

? ? ? ?listener = new EventListener() {

? ? ? ? ? ?public void onEvent(Event e) {

? ? ? ? ? ? ? ?doSomething(e);

? ? ? ? ? ?}

? ? ? ?};

? ?}

?

? ?public static SafeListener newInstance(EventSource source) {

? ? ? ?SafeListener safe = new SafeListener();

? ? ? ?source.registerListener(safe.listener);

? ? ? ?return safe;

? ?}

}

?

?

3.3 线程封闭

? ??

? ? 如果仅在单线程里访问数据,则不需要同步。

? ? 应用例子:

? ? swing中大量使用线程封闭技术, ? swing常见错误,其他线程使用了该被封闭的对象

? ? jdbc的Connection对象,web服务器的请求线程从连接池中获取一个connection对象,直到使用完后返

?

回给连接池。在此期间,不会把connection分配给其他线程

? ? ThreadLocal :struts2等框架,把请求参数通过ThreadLocal放在封闭在自己线程中

? ??

? ? 方式有Ad-hoc、栈封闭、和ThreadLocal

? ??

? ? (5.3.2 的串行线程封闭是否属于Ad-hoc呢)

? ??

3.3.1 Ad-hoc 线程封闭(Ad-hoc拉丁语 for this 。专门的、特别设定的)

? ? ?封闭的职责完全由程序来负责,很脆弱

3.3.2 栈封闭

3.3.3 ThreadLocal类

?

? ? ? 例子:

? ? ? ?private static ThreadLocal<Connection> connectionHolder

? ?= new ThreadLocal<Connection>() {

? ? ? ?public Connection initialValue() {

? ? ? ? ? ?return DriverManager.getConnection(DB_URL);

? ? ? ?}

? ?};

?

public static Connection getConnection() {

? ?return connectionHolder.get();

}

?

? ?

? ? ? ? ?

? ? ? ? ?

? ? ? ? ?

? ? ? 可以看成把ThreadLocal(T)看成Map<Thread,T>,但不仅如此,提供了当线程停止后,T会被作为垃

?

圾回收

? ? ? 应用程序框架大量使用ThreadLocal。J2EE容器需要将一个事务上下文( Transaction Context )与

?

某个执行的线程关联起来

? ? ? 开发人员经常滥用ThreadLocal ,ThreadLocal 类似全局变量,它能降低代码的重用性。引入耦合。

?

操作要额外小心

? ? ??

? ? ? 扩展:

? ? ? spring DAO模板等底层技术,ThreadLocal是必须攻克的

? ? ??

? ? ??

? ? ??

3.4 不变性

? ? 3.4.1 Final域

? ? 3.4.2 示例:使用Volatile类型发布不可变对象

3.5 安全发布

?

? ?Immutable objects can be used safely by any thread without additional synchronization, even?

?

when synchronization is not used to publish them.

? ?

3.5.3 安全发布常用模式

? ? ? 可变对象必须通过安全的方式发布的,发布的

? ? ?To publish an object safely, both the reference to the object and the object‘s state must?

?

be made visible to other threads at the same time. A properly constructed object can be safely?

?

published by:

?

Initializing an object reference from a static initializer;(

怎么理解?

public static Holder holder = new Holder(42);

Static initializers are executed by the JVM at class initialization?

?

time; because of internal synchronization in the JVM, this mechanism is guaranteed to safely?

?

publish any objects initialized in this way [JLS 12.4.2].

? ? ? )

?

Storing a reference to it into a volatile field or AtomicReference;

?

Storing a reference to it into a final field of a properly constructed?

?

object; or

?

Storing a reference to it into a field that is properly guarded by a?

?

lock.

?

?

3.5.4 事实不可变对象

? ? ? 技术上可变,事实上不可变

? ? ??

3.5.5 ?可变对象

?

The publication requirements for an object depend on its mutability:

?

Immutable objects can be published through any mechanism;

?

Effectively immutable objects must be safely published;

?

Mutable objects must be safely published, and must be either?

?

threadsafe or guarded by a lock(3.5.3介绍的安全发布模式)

3.5.6 ?安全的共享对象,即最后如下总结

?

?

总结:

??

? The most useful policies for using and sharing objects in a concurrent program are:

?

1、线程封闭 Thread-confined. A thread-confined object is owned exclusively by and?

?

confined to one thread, and can be modifled by its owning thread.

2、只读共享 Shared read-only. A shared read-only object can be accessed concurrently?

?

by multiple threads without additional synchronization, but cannot be modified by any thread.?

?

Shared read-only objects include immutable and effectively immutable objects.

3、线程安全的对象的共享 Shared thread-safe. A thread-safe object performs?

?

synchronization internally, so multiple threads can freely access it through its public?

?

interface without further synchronization.

4、保护对象 Guarded. A guarded object can be accessed only with a specific lock held.?

?

Guarded objects include those that are encapsulated within other thread-safe objects and?

?

published objects that are known to be guarded by a specific lock.

?

?

?

?

?

?

java并发编程实战-第3章-对象的共享

原文:http://zhouchaofei2010.iteye.com/blog/2243277

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!