Java并发编程-线程安全性

来源:互联网 发布:过墙软件 编辑:程序博客网 时间:2024/05/16 12:33

线程安全性

1.无状态的类(没有数据域)一定是线程安全的

2.竞态条件:比如多个线程对同一个变量i同时执行i+=1(先读取i,然后加1,然后修改i),就会出现竞态条件
最常见的竞态条件就是先检查后执行操作,即通过一个可能失效的观测结果来决定下一步的动作。

3.AtomicLong,AtomicInteger等是线程安全的。

4.多线程中,如果两个变量不是相互独立的,即一个变量的值会依赖另一个变量的值,那么在更新时,必须保证两个变量同时更新,也就是必须作为一个原子操作来更新两个变量。
“要保持状态的一致性,就需要在单个原子操作中更新所有相关的状态变量”

5.synchronized(互斥锁,只能有一个线程持有这种锁),称为Intrinsic Lock或者Monitor Lock。
synchronized(Object object){} //对object对象加锁
public synchronized void xxx(){}//对this对象加锁
进入代码块时自动获得锁,退出代码块时自动释放锁。
当一个线程A正在占有该锁,而另一个线程B想要获取该锁时,B将会被阻塞或者等待。

6.重入:当一个线程A已经占用锁时,如果A再次尝试获取该锁是会成功的。
synchronized是可重入的。
重入的实现:为每个锁关联一个获取计数值和一个所有者线程,当线程A第一次获取该锁时,计数值加1变为1,当线程A再次获取该锁(重入)时,计数值再次加1变为2。每当退出一个同步代码块,计数值就减1,当计数值为0时,该锁才被释放。
重入可以避免死锁

public class Base{    pubic synchronized void doSomething(){        ...    }}public class Son{    public synchronized void doSomething(){        super.doSomething();    }}public class Main{    public static void main(String[] args){        Base base = new Son();        base.doSomething();   //此处若不能重入则会导致死锁。因为在一个线程中,base对象会被加两次锁。    }}

重入意味着获取锁的粒度是“线程”,(即多个线程去争用一个锁,最终一个线程获取到),而不是“调用”。

7.每个共享的和可变的变量都应该只由一个锁来保护

8.对于多个必须同步改变的变量,可以将他们封装在一个对象中,然后对该对象加内部锁。但是必须保证该类内部的操作能够对变量进行同步改变。