1.什么是线程安全性
当多个线程访问某个类时,不管运行时环境采用何种调度方式或者现线程将如何交替执行,并且在主调代
码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么这个类就是线程安全的。
在线程安全的类中封装了必要的同步机制,因此调用者无需进一步采取同步措施。
无状态对象一定是线程安全的。
2.竞态条件
在并发编程时,由于不恰当的执行时序而出现不正确的结果。
比如,先检查后执行。
3.加锁机制
要保持状态的一致性,就需要在单个原子操作中更新所有的状态变量。
3.1内置锁
Java提供了一种内置的锁机制来支持原子性,即同步代码块,使用synchronized修饰,synchronized修饰方法,则整个方法是一个同步代码块。
同步代码块:
synchronized (lock){ // 访问或修改由锁保护的共享状态 }
同步方法:
/** *整个方法作为同步代码块 */ synchronized void function1() { }
对整个方法使用synchronized加锁,同时只能有一个线程可以执行该方法,会使执行性降低,所以一般情况下尽量不要对整个方法加锁,而应该使用较小的同步代码块。
3.2重入
可重入是指,某个线程可以重复获得自己已经持有的锁,而不会阻塞,即获取锁的粒度是“线程”。
4.用锁保护状态
对于可能被多个线程同时访问的可变状态变量,在访问它是都需要持有同一个锁,即该状态变量是由这个锁保护的。
对于包含多个变量的不变性条件,其中涉及的所有变量都要由同一个锁来保护。
5.活跃性与性能
通常,在简单性与性能之间存在相互制约关系,当实现某个同步策略时,一定不要盲目的为了性能而牺牲简单性(这样可能会破坏安全性)。
当执行时间较长的计算或者可能无法快速完成的操作时一定不要持有锁(比如,网络或控制台I/O,数据库查询等)