对象的状态 : 指存储在状态变量中的数据
同步机制:
synchronized,它提供了一种独占锁,但同步这个术语还包括volatile类型的变量,显式锁以及原子变量。
注意 : 如果当多个线程访问同一个可变的状态变量时没有使用合适的同步,那么程序就会出错,可以通过下面的三种方法来解决。
不在线程之间共享该状态变量、将状态变量修改为不可变的变量、在访问状态变量时使用同步。
一、线程安全性:当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类时线程安全的。线程安全类中封装了必要的同步机制,不须客户端采取同步措施
无状态的对象一定是线程安全的
二、原子性:为了避免竞态条件,就必须在某个线程修改该变量时,通过某种方式防止其他线程使用整个变量
1:竞态条件 :由于不恰当的执行时序而出现不正确的结果,例如延迟初始化就会产生这样的情况。
2:要保持状态的一致性,就需要在单个原子操作中更新所有相关的状态变量
三、加锁机制
1:java内置锁(互斥锁) : java提供了一种内置的锁机制来支持原子性(同步代码块)
同步代码块包括两部分,一个作为锁的对象引用、一个作为由这个锁保护的代码块
以关键字synchronize来修饰的方法是一种横跨整个方法体的同步代码块,其中该同步代码块的锁就是方法调用所在的对象
静态的synchronized方法以Class对象作为锁
2::重入
当某个线程请求一个由其他线程持有的锁时,发出请求的线程就会阻塞。重入的一种实现方法是,为每个锁关联一个获取计数值和一个所有者线程。
当计数值为0时,这个锁就被认为是没有被任何线程持有。当线程请求一个未被持有的锁时,jvm将记下锁的持有者,并且将获取计数值置为1。如果同一个线程再次获取这个锁,计数值将递增,而当线程退出同步代码块时,计数器会相应地会相应地递减。当计数值为0时,这个锁将被释放。
如果没有使用重入:会发生死锁
public class A {
public synchronized void doSomething(){
}
}
public class B extends A {
public synchronized void doSomething(){
super.doSomething();
}
}
四、用锁来保护状态
如果用同步来协调某个变量的访问,那么在访问这个变量的所有位置上有需要使用同步
使用锁来对某个变量的访问时,在访问变量的所有位置上都要使用同一个锁
对于可能被多个线程同时访问的可变状态变量,在访问它时都需要持有同一个锁