“共享”意味着变量可以由多个线程同时访问,而“可变”则意味着变量的值在其周期内是可以发生变化的。
一个对象是否是线程安全的,取决于它是否被多个线程访问。
当多个线程的访问某个状态变量并且其中某一个线程执行写操作时,必须采用同步机制来协同这些线程对变量的访问。java的同步机制是关键字synchronized,提供了一个独占的加锁方式。
当多个线程访问同一个可变的状态变量时,可以使用以下三种方式避免错误:
1、不在线程之间共享该变量状态。
2、将该变量状态修改为不可变的变量。
3、在访问变量中使用同步机制。
线程安全性:某个类的行为与其规范完全一致。在良好的规范中通常会定义各种不变性条件(Invariant)来约束对象的状态,以及定义各种后验条件(Postcondition)来描述对象的操作结果。
线程安全的类: 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程如何的交替运行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。无状态对象一定是线程安全的,大多数servlet都是无状态的。
竞态条件: 多个线程执行时序不同而导致不同的结果。
复合操作:多个原子操作组合在一起的操作称为复合操作。只有在复合操作中出现竞态条件问题。
1、内置锁,
Java提供了一种内置的锁机制来支持原子性:同步代码块(Synchronized block),关键字为synchronized,用该关键字来修饰方法就是一种跨越整个方法的同步代码块。
Java内置锁相当于一种互斥体(或互斥锁),就意味着最多只有一个线程持有这种锁。
2、重入
重入:某个线程试图获得一个已经由它本身自己持有的锁,那么这个请求就会 成功。重入意味着锁的操作粒度是“线程”,而不是"调用"。
比如下面的代码块:


1 public class People { 2 public synchronized void doSomething(){ 3 System.out.println("doSomething"); 4 } 5 } 6 7 8 public class XiaoMing extends People { 9 public synchronized void doSomething(){ 10 System.out.println("xiaoMing do something"); 11 super.doSomething(); 12 } 13 }
如果内置锁是不可以重入的话,那么在条用子类的doSomething()时将无法获得父类的锁,因为这个锁已经被持有,从而线程就被永远停顿下去。重入则避免了这种情况的发生。