Java 中的线程同步方案

Java 中的线程同步方案|线程安全的实现方法

同步是指在多个线程并发访问共享数据时保证共享数据在同一时刻只被一条线程使用。

1. 互斥同步即阻塞同步

临界区、互斥量、信号量都是常见的互斥实现方式。

在 Java 中,最基本的同步方式就是 synchronized 关键字

被 synchronized 修饰的同步块对同一条线程来说是可重入的。这意味着同一线程反复进入同步块也不会出现自己把自己锁死的情况

被 synchronized 修饰的同步块在持有锁的线程执行完毕并释放锁之前,会无条件的阻塞后面其他线程的进入。

在 JDK 5 起,Java 提供了 java.util.concurrent 包,其下的 J.U.C.locks.Lock 接口是 Java 的另一种全新的同步互斥手段。

重入锁( ReentrantLock )是 Lock 接口最常见的一种实现,ReentranLock 相较于 synchronized 增加了一些功能

  • 等待可中断:当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情
  • 公平锁:公平是指:多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁;synchronized 是非公平的,ReentranLock 在默认情况下也是非公平的,但可以通过带布尔值的构造函数要求使用公平锁。
  • 锁绑定多个条件:指一个 ReentranLock 对象可以同时绑定多个 Condition 对象。在 synchronized 中,锁对象的 wait() 和它的 notify() 或者 notifyAll() 方法配合可以实现一个隐含的条件,如果要和多个条件关联时,就不得不添加一个锁;而 ReentranLock 只需多次调用 newCondition() 方法即可
阻塞同步的缺点

在主流的 Java 虚拟机实现中,Java 的线程是映射到操作系统的原生内核线程之上的(内核线程实现),如果需要阻塞或唤醒一条线程,则需要操作系统来帮忙完成,这将会导致用户态到核心态的转换、维护锁计数器和检查是否有被阻塞的线程需要被唤醒等开销

2. 非阻塞同步

基于冲突检查的乐观并发策略。

不管风险先进行操作,如果没有其他线程争用共享数据,那操作就直接成功了;如果共享的数据的确被争用,产生了冲突,再进行其他的补偿措施,最常用的措施就是不断的重试,直到出现没有竞争的共享数据为止。

3. 无同步方案

要保证线程安全,也并非一定要进行阻塞或非阻塞同步,同步与线程安全两者并没有必然的联系。同步只是保障存在共享数据争用时正确性的手段,如果能让一个方法本来就不涉及共享数据,那它自然就不需要任何同步措施去保证其正确性,即天生线程安全的代码

  • 可重入代码:指可以在代码执行的任何时刻中断它,转而去执行另外一段代码(包括递归调用他本身),而在控制权返回后,原来的程序不会出现任何错误,也不会对结果有影响。

    如果一个方法的返回结果是可以预测的,只要输入了相同的数据,就都能返回相同的结果,那它就满足可重入性的要求,当然也就是线程安全的

  • 线程本地存储:即将需要共享数据的代码保证在同一条线程中执行
    (摘录自:《深入理解 Java 虚拟机》)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值