1.无状态的对象一定线程安全,因为没有共享状态,题目都在访问不同的实例。
2.当某个计算的正确性取决于多个线程的交替执行时序时,就会发生竞态条件。
3.当无状态类中添加一个状态时,如果该状态由线程安全对象来管理,那这个类仍是线程安全的。当添加多个变量时不一定,因为多个状态变量之间往往会存在约束,当一个变量更新时需要在同一个原子操作中对其他变量进行同时更新,而线程安全类只能保证对单个变量的操作是安全的。
加锁机制
1.内置锁
java提供一种内置的锁机制来支持原子性:同步代码块。以关键字Sychronized来修饰的方法是一种跨整个方法体的同步代码块,其锁就是方法调用所在的对象。若A线程尝试获得一个B线程持有的锁,A线程必须等待或者阻塞。
2.重入
内置锁是可重入的,线程可以获取已经由自己持有的锁。这意味锁的操作粒度是“线程”而不是“调用”。重入锁一种实现方法是关联一个获取计数值和所有者线程。
以下代码中子类和父类中都获取子类的锁。
public class Widget {
public synchronized void doSomething() {...}
}
public class LoggingWidget extends Widget {
@Override
public synchronized void doSomething() {
System.out.println(...);
super.doSomething();
}
}
关于@guardedby注释
1、@GuardedBy( "this" ) 受对象内部锁保护
2、@GuardedBy( "fieldName" ) 受 与fieldName引用相关联的锁 保护。
3、@GuardedBy( "ClassName.fieldName" ) 受 一个类的静态field的锁 保存。
4、@GuardedBy( "methodName()" ) 锁对象是 methodName() 方法的返值,受这个锁保护。
5、@GuardedBy( "ClassName.class" ) 受 ClassName类的直接锁对象保护。而不是这个类的某个实例的锁对象。
当有执行时间较长的计算或者可能无法快速完成的操作时,一定不要持有锁。