Java 多线程概念

线程和进程区别

进程是程序执行的过程,线程是轻量级进程,程序执行的分支

  1. 进程是资源分配单位,线程是资源调度单位;
  2. 线程是进程划分成的更小的运行单位;
  3. 进程相互独立,同一进程中的线程可能会相互影响;
  4. 线程执行开销小,但不利于资源的管理和保护;而进程正相反

为什么要用多线程

  1. 提高程序运行效率(将大任务分解成互不依赖的小任务,每个任务用一个线程执行,大任务的执行时间可以降到等于执行时间最长的小任务时间);
  2. 提高cpu利用率(线程池,多个同类任务并发执行,并发数取决于);

什么是线程安全

  1. 多个线程并发执行,结果正确
  2. 三个原则:原子性、可见性、有序性

怎么思考线程安全问题

  1. 能不能保证操作的原子性,考虑使用Atomic包
  2. 能不能保证操作的可见性,考虑使用volatile
  3. 批量操作,避免重复创建线程,使用线程词
  4. 集合,考虑concurrent包下集合类
  5. 锁,synchronized,lock包

死锁

当前线程拥有其他线程需要资源,当前线程还需要其他线程资源,都不释放拥有的资源

产生死锁的必要条件

  1. 互斥
  2. 请求与保持
  3. 不可剥夺
  4. 循环等待

避免死锁

  1. 一次性获取所有
  2. 等待一定时间主动释放占有资源
  3. 按某种顺序请求资源(哈希,银行家算法……)

CAS

比较并交换,如果等于原来的值就更新为新的值,原子性操作,对应到CPU指令为cmpxchg

为什么要用CAS

并发环境中,操作共享变量时,会产生线程安全问题,可以使用Synchronized对共享变量加锁,确保只有一个线程能够修改共享变量,但是有些情况下这样开销太大,例如对一个值进行累加,这种情况下可以用Atomic包里的类,这些类底层就是使用CAS实现的,而CAS相当于没有加锁,多个线程可以直接操作,在实际修改时在判断是否成功,比锁更高效

CAS缺点

带来ABA问题

ABA问题:CAS更新时只比较当前值和内存值是否相等,但是假设线程A读到当前值是1,可能线程B把值改为2,线程C又把值改为1,这是线程A修改这个变量是可以成功的,对于A来说值未改变,但是这样是不合理的,值已经被B、C修改了
解决方案:使用AtomicStampedReference类,原理是增加了版本号,即比较内存值+版本号是否一致

为什么LongAdder 对象,比 AtomicLong 性能更好(减少乐观锁的重试次数)

AtomicLong 是多线程操作一个资源,高并发时,只有一个成功,其他的不断自旋,浪费cpu资源
LongAdder将要操作的资源分散到cell数组中,每个线程对cell的value进行CAS操作,大大降低失败次数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值