《Java 并发编程实战》—— 安全性、活跃性以及性能问题

07 | 安全性、活跃性以及性能问题

安全性问题

线程是否安全?本质上就是正确性,而正确性的含义就是程序按照我们期望的执行

存在共享数据并且该数据会发生变化,通俗地讲就是有多个线程会同时读写同一数据

  • 数据竞争:当多个线程同时访问同一数据,并且至少有一个线程会写这个数据的时候,如果我们不采取防护措施,那么就会导致并发 Bug。

当产生数据竞争时,不仅仅加锁就能解决这个问题的,要合理的利用锁的范围能力,例如:方法被同时调用,不是先拿set的锁,是先拿get的锁。先计算参数,后调用方法

  • 竞态条件:指的是程序的执行结果依赖线程执行的顺序

面对数据竞争和竞态条件问题:用互斥这个技术方案,而实现互斥的方案有很多,CPU 提供了相关的互斥指令,操作系统、编程语言也会提供相关的 API。从逻辑上来看,我们可以统一归为:

活跃性问题

除了死锁外,还有两种情况,分别是“活锁”和“饥饿

活锁:有时线程虽然没有发生阻塞,但仍然会存在执行不下去的情况

例如:路人甲从左手边出门,路人乙从右手边进门,两人为了不相撞,互相谦让,路人甲让路走右手边,路人乙也让路走左手边,结果是两人又相撞了。

饥饿:指的是线程因无法访问所需资源而无法执行下去的情况

解决饥饿:一是保证资源充足,二是公平地分配资源,三就是避免持有锁的线程长时间执行

性能问题

使用“锁”要非常小心,但是如果小心过度,也可能出“性能问题”。“锁”的过度使用可能导致串行化的范围过大,这样就不能够发挥多线程的优势了,而我们之所以使用多线程搞并发程序,为的就是提升性能。

方法:

  • 最好的方案自然就是使用无锁的算法和数据结构了,例如线程本地存储 (Thread Local Storage, TLS)、写入时复制 (Copy-on-write)、乐观锁等;Java 并发包里面的原子类也是一种无锁的数据结构;
  • 减少锁持有的时间,例如使用细粒度的锁,一个典型的例子就是 Java 并发包里的 ConcurrentHashMap,它使用了所谓分段锁的技术(这个技术后面我们会详细介绍);还可以使用读写锁,也就是读是无锁的,只有写的时候才会互斥。
    学习自:https://time.geekbang.org/column/intro/100023901?tab=catalog
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值