JCIP_2_线程安全性笔记总结

来源:互联网 发布:软件加密锁编程技巧 编辑:程序博客网 时间:2024/05/17 09:42

JCIP_2_线程安全性笔记总结

编写线程安全代码的核心在于对状态访问操作进行管理,特别是对共享的和可变的状态的访问,共享意味着变量可以由多个线程同时访问,而可变则意味着变量的信息在其生命周内是可以发生变化的。

线程安全性

当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。

避免线程安全性问题

1.不在线程之间共享

2.无状态对象一定是线程安全的

3.使用不可变对象(将状态变量修改为不可变的变量)

4.在访问共享的状态时使用同步

原子性

1.竞态条件,当某个计算的正确性取决于多个线程交替执行时序时,就会发生竞态条件。比较典型的就是先检查后执行(Check-Then-Act

2.复合操作,复合操作包含了一组必须以原子方式执行的操作以确保线程安全性。

3.原子变量类,JDK1.5之后的版本加入了java.util.concurrent.atomic包中包含了一些原子变量类。

内置锁

同步代码块(synchronizedblock),同步代码块有两部分,一个作为锁的对象,一个作为由这个锁保护的代码块。每个Java对象都可以用做一个实现同步的锁,这些锁被称为内置锁或监视器锁,线程在进入同步代码块这前会自动获得锁,在退出同步代码块时自动释放锁。

获得内置锁的唯一途径就是进入由这个锁保护的同步代码块或方法。

Java的内置锁相当于一种互斥体,最多只有一个线程能持有这种锁,因此使用内置锁保护的同步代码块会以原子方式执行。并发环境中的原子性与事务应用程序中的原子性有着相同的语义(一组语句作为一个不可分割的单元被执行)。

锁重入

当某个线程请求一个由其它线程持有的锁时,发出请求的线程就会阻塞,由于内置锁是可重入的,如果某个线程试图获得一个已经由它自己持有的锁,那么这个请求就会成功。

重入意味着获取锁的操作的粒度是线程而不是具体某个调用。

加锁机制

1.要保持对共享资源状态的一致性,就需要在同一个原子操作中处理所有相关的状态变量。

2.对象内置锁与其状态之间没有内在的关联

3.对于可能被多个线程访问的可变状态变量,读写该变量都必须持有同一个锁。

4.并非所有数据都需要锁的保护,只有被多个线程同时访问的可变数据才需要通过锁来保护。

5.对于每个包含多个变量的不变性条件,其中涉及的所有变量都需要由同一个锁来保护。

6.并不是单纯的使用内置锁就可以避免竞态条件,内置锁可以确保单个操作的原子性,但如果把多个操作合并为一个复合操作,还是需要额外的加锁机制。

活跃性和性能

通常,在简单性与性能之间存在着相互制约的因素,当实现某个同步策略时,一定不要盲目地为了性能而牺牲简单性(这可能会破坏安全性)。

当执行时间较长的计算或者可能无法快速完成的操作时(网络I/O、控制台I/O)一定不要持有锁。

整理

资料

1Java并发编程实践

2Java Concurrency in Practice

3Java线程


0 0
原创粉丝点击