剑客
关注科技互联网

java 线程安全性

并发编程中,由于不恰当的执行顺序出现不正确的运行结果,这样的情况叫:竞态条件。最常见的的例子就是,先检查在执行(单例模式的实现)。

要避免竞态条件问题,就必须在某个线程修改该变量的时候,通过某种方式防止其他线程使用这个变量。一种是把变量操作变成原子操作,另外一种就是加锁。

要保持状态的一致性,就需要在单个原子操作中更新所有相关的状态变量。

内置锁

Java 提供了一种内置的锁机制来支持原子性: synchornized。

每个 Java 对象都可以当作一个实现同步的锁,这些锁称为内置锁或者监视器锁。

Java 的内置锁相当于一种互斥锁,这就是说最多只有一个线程能持有这个锁。

内置锁是可以重入的。重入意味着获取锁的操作的粒度是线程,而不是调用。

重入的一种实现方式,为每个锁关联一个获取计数值和一个所有者线程。当计数是0的时候,这个锁就认为是没有被线程占用。当线程请求一个未被占用的锁的时候,JVM 将记下锁的持有者,并且将获取计数值设置成1。如果同一个线程再次获取这个锁,计数值将递增,当线程退出同步代码块,计数器递减。当计数器是0,这个锁被释放。

对于可能被多个线程同时访问的可变状态变量,在访问它的时候都需要持有同一个锁,这种情况下,我们称状态变量是由这个锁保护的。

内存可见性

当在一个线程当中修改了一个变量,另外的一个线程读取这个变量,如果是没有同步的情况下,那么可能另外的线程读取的时候就是旧的数据。

内置锁可以确保,某个线程以一种可预测的方式来查看另外一个线程的执行结果。

加锁的含义不仅仅局限于互斥性,还包括了内存可见性。

Java 提供了 volatile 变量,用来确保将变量的更新操作通知到其他线程。

volatile 不能确保递增操作(x++)的原子性。

加锁既可以确保可见性又可以确保原子性,而 volatile 变量只能确保可见性。

—EOF—

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址