第10章 并发

Item 66 同步访问共享的可变数据

1 Java语言规范保证:读/写一个变量是原子的,除非该变量是long/double

2 虽然语言保证了线程读取原子数据的时候不会看到任意数值,但并不保证一个线程的写入值对另一个线程可见。

3 使用Thread.stop会导致数据遭到失败。要阻止一个线程妨碍另一个线程,建议让第一个线程轮询,共享一个boolean型域。

4  p230页示例修正方法:

    A 修改boolean域方法使用synchronzied

    B 使用volatile修饰boolean域。但如果volatile i; i++的话,i++仍然不是原子的,这是可以用到AtomicLong来修饰i变量。

5 共享一个对象的引用:一个线程修改该对象,同步共享对象引用的动作。该对象事实上不可变 effectively immutable

6 安全发布:将这种对象引用从一个线程传递到其它线程。

7 安全发布方法:

    A 保存在静态域中,作为类初始化一部分

    B 保存在volatile域,final域或通过正常锁定访问的域中

    C 放在并发的集合中

8 总之,多个线程共享可变数据时,每个读写该数据的线程必须执行同步。

 

Item 67 避免过度同步

1 在同步区域外调用外来方法:开放调用。可以避免死锁,增加并发性。

2 应该在同步区做尽可能少的工作,如果必须执行某个耗时动作,也应该设法把改动做移到同步区外

3 如果某类并发,则应使其内部安全,否则不要在内部同步,让客户必要时在外部同步。如StringBuffer总是由StringBuilder代替。

4 如果内部同步了类,则应采用方法提高并发:分拆锁、分离锁、非阻塞锁。

 

Item 68 executor/task优先于线程

1 尽量不用线程处理队列请求,而是调用静态工厂(java.uti.concurrent.Executors),产生不同的executor service,称作线程池thread pool(ThreadPoolExecutor类)

2 现在工作单元和执行机制分开了。现在关键的抽先是:task。分两种:Runnable / Callable(有返回值)

 

Item 69 并发工具优先于wait/notify

1 java.uti.concurrent包括三种高级并发工具:

    A Executor Framework

    B 并发集合 Concurrent Collection

    C 同步器 Synchronizer

2 同步器是协调线程的对象:倒计数锁存器CountDownLatch  /  Semaphore

3 优先使用System.nanoTime,而不是System.currentTimeMills

4 始终应该使用wait循环模式调用wait方法,不要在循环外调用wait方法。

5 优先使用notifyAll,而不是notify,当不确定哪个等待线程先执行时。

 

Item 70 线程安全的文档化

1 查看文档中是否出现Synchronized修饰符来确定一个方法是否线程安全是错误的:javadoc并未在其输出中包含Synchronized

2 线程安全中种类:5种

    A 不可变

    B 无条件线程安全

    C 有条件线程安全

    D 非线程安全

    E 线程对立

3 私有锁对象模式:

不要使用共有可访问锁对象,而要使用私有锁对象,避免攻击。通过对这个对象加锁/解锁达到同步目的,比如

private final Object lock = new Object();

这种锁对象只能用于无条件线程安全类。

有条件线程安全类不能使用是因为,他们必须在文档说明,什么环境下使用,客户端程序必须获得哪把锁。

私有锁对象模式很适用于转为继承而设计的类,如果使用该类实例作为锁对象,子类很容易无意中妨碍基类动作。

 

Item 71 慎用延迟初始化 lazy initialization

1 "除非绝对必要,否则不要这么做"

虽然降低了初始化类/创建实例的开销,但增加了访问被延迟对象的开销

2 并发时,如果对静态域延迟初始化,则使用lazy initialization holder class 模式

3 并发时,如果对实例域延迟初始化,则使用双重检查模式double-check idiom,两次检查域的值

第一次检查时没有锁定,看这个域是否初始化了

第二次检查时有锁定

 

Item 72 不要依赖线程调度器

1 最好确保可运行线程平均数量不明显多于处理器数目

A 让每个线程做有意义的工作,然后等待更多有意义的工作

B 如果不是,则不该运行

2 如果某些线程无法获得足够的CPU时间:不应用Thread.yield和调整优先级来修正,其不具有可移植性

 

Item 73 避免使用线程组

1 线程组Thread Group:初衷是作为一种隔离applet的机制

2 唯一优势:JDK1.5前,线程抛出未被捕获的异常时,ThreadGroup.uncaughtException是获得控制权的唯一方式

3 可以忽略不用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值