7. 安全性、活跃性以及性能问题 -理论基础

1. 安全性问题

线程安全:程序按照我们的期望执行,不出现意外情况。实际上只有一种情况需要分析:存在共享数据并且该数据会发生变化,通俗地讲就是有多个线程会同时读写同一数据。那如果能够做到不共享数据或者数据状态不发生变化,不就能够保证线程的安全性了嘛。有不少技术方案都是基于这个理论的,例如线程本地存储(Thread Local Storage,TLS)、不变模式等

数据竞争(data race): 多个线程同时访问同一数据,并且至少有一个线程会写这个数据.
竞态条件(Race Condition): 程序的执行结果依赖线程的执行顺序。如下:

if (状态变量 满足 执行条件) {
  执行操作
}

当某个线程发现状态变量满足执行条件后,开始执行操作;可是就在这个线程执行操作的时候,其他线程同时修改了状态变量,导致状态变量不满足执行条件了。

2. 活跃性问题

指的是某个操作无法执行下去,包括死锁活锁饥饿
1. 活锁
线程没有发生阻塞,但依然执行不下去。形象比喻:甲从左手边出门,乙从右手边进门,为了不碰撞,互相谦让,甲从右手边出门,乙从左手边出门,两人还是碰撞了。

解决方式:尝试等待一个随机的时间。

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

解决方式:使用公平锁,线程的等待是有顺序的,排在等待队列前面的线程会优先获得资源。

3. 性能问题

锁”的过度使用可能导致串行化的范围过大,这样就不能够发挥多线程的优势了,而我们之所以使用多线程搞并发程序,为的就是提升性能。

阿姆达尔(Amdahl)定律,代表了处理器并行运算之后效率提升的能力:
在这里插入图片描述

  • n , CPU 的核数;
  • p ,并行百分比,(1-p),串行百分比了;
  • 假设(1-p)是 5%,n无穷大,加速比 S 的极限就是 20。也就是说,如果我们的串行率是 5%,那么我们无论采用什么技术,最高也就只能提高 20 倍的性能。

解决方案:

  • 第一,既然锁带来性能问题,最好是使用无锁的算法和数据结构,例如线程本地存储 (Thread Local Storage, TLS)、写入时复制 (Copy-on-write)、乐观锁等;Java 并发包里面的原子类也是一种无锁的数据结构;Disruptor 则是一个无锁的内存队列,性能都非常好……

  • 第二,减少锁持有的时间。分段锁,读写锁。

性能指标:

  • 吞吐量:指的是单位时间内能处理的请求数量。吞吐量越高,说明性能越好。
  • 延迟:指的是从发出请求到收到响应的时间。延迟越小,说明性能越好。
  • 并发量:指的是能同时处理的请求数量,一般来说随着并发量的增加、延迟也会增加。所以延迟这个指标,一般都会是基于并发量来说的。例如并发量是 1000 的时候,延迟是 50 毫秒。

4. 总结

并发编程是一个复杂的技术领域,微观上涉及到原子性问题、可见性问题和有序性问题,宏观则表现为安全性、活跃性以及性能问题。

我们在设计并发程序的时候,主要是从宏观出发,也就是要重点关注它的安全性、活跃性以及性能。安全性方面要注意数据竞争和竞态条件,活跃性方面需要注意死锁、活锁、饥饿等问题,性能方面我们虽然介绍了两个方案,但是遇到具体问题,你还是要具体分析,根据特定的场景选择合适的数据结构和算法。

5. 课后思考

Java 语言提供的 Vector 是一个线程安全的容器,有同学写了下面的代码,你看看是否存在并发问题呢?

void addIfNotExist(Vector v, Object o){
  if(!v.contains(o)) {  //1 
    v.add(o);   // 2
  }
}

我的思考:虽然contains()和add()两个方法都加锁了,但是存在竞态问题。AB两个线程先后执行了代码1,但还为能执行代码2,假设此时线程A执行了代码2,显然线程B再执行代码2的时候就有问题。
单个方法是原子性的,但是contains()和add()组合起来不一定是原子性的。
l

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值