并发编程学习(6) —— 线程的安全问题、活跃问题和性能问题

并发编程中我们注意的方面有很多,但是最主要的还是这三个方面:安全性问题、活跃性问题、性能问题。

安全性问题

线程安全是什么?其实简单来说就是**线程能按照我们的期望来执行。**但是在并发编程中却没那么美好,在并发编程学习(2) —— 并发编程Bug源头中我们介绍了并发Bug的主要源头:

  1. 可见性
  2. 原子性
  3. 有序性

一般在存在共享变量并且该变量会改变,同时有至少一个线程写这个变量这种情况下才会考虑这三种情况,也可以称这种情况为数据竞争。除此之外,程序的执行结果是依赖于线程执行的顺序,也就是所谓的竞态条件,下面用代码来举例:

public class ThreadTest {
    int values = 0;
    
    sychronized int getValues(){
        return values;
    }
    
    sychronized void addOne(){
        values += 1;
    }
}

如果有两个线程同时调用get()+1,最终values的结果不是2,而是1,因为synchronized只能保证get()这个操作的安全性,不能保证get()+1这个组合操作的安全性,因此只有当线程串行化时就能解决这些问题,JAVA的解决方法里就提供了锁。

活跃性问题

活跃性问题指的是线程因为某种原因而导致无法执行下去。线程的活跃性问题除了前面介绍的死锁外,还有活锁饥饿

活锁

比起死锁那种你我互不相让的情况,活锁就是双方互相其谦让引起的冲突。现实中有甲乙两个人,做什么都互相谦让,你从东门出我在西门出,但有一天,在甲乙两人在路上碰到,甲往左侧挪想让乙先过,乙往右侧挪想让甲先过,这样就会造成相撞,在现实中甲乙能够通过沟通来解决这种情况,但在程序中,只会继续相撞下去,造就成所谓的活锁

那么怎么解决活锁?最好的方法就是设置一个等待随机时间,甲乙相撞各自设置一个等待随机时间,甲乙在各自的随机时间结束后挪到另一方,这样就能解决活锁问题。

饥饿

引起饥饿问题最主要的是线程的优先级。优先级低的线程很多时候会被优先级高的线程取代,造成优先级低的永远无法执行,造成“饥饿”。另外长时间持有锁也会造成“饥饿”问题。

那么解决饥饿的方法有以下三种:

  1. 避免持有锁长时间的执行。
  2. 公平的分配资源。
  3. 保证资源充足

性能问题

性能问题主要考察的是程序三个方面:

  1. 并发量:同一时刻处理多个请求,并发量越多,延迟也越多。
  2. 吞吐量:单位时间内处理的请求数量越高性能越好。
  3. 延迟:从发出请求到响应的时间。一般时间越短性能越好。

总结

在一开始只想提高CPU使用率,到后来优化后带来的种种问题,说明很多东西都有两面性,并不是所有优化后带来的效果会比优化前好,同时还要考量优化后可能带来问题,如何规避这些问题都是非常重要的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值