浅谈线程安全问题

共享内存的原因

在Java内存模型中,分为主内存和线程工作内存,线程使用共享数据时,都是先从主内存中拷贝到工作内存,使用完成之后再写入主内存,可以理解为线程之间通讯是通过共享内存的方式实现的。

线程安全需要满足的特点

  • 原子性:对数据的操作不会受其他线程打断,意味着一个线程操作数据过程中不会插入其他线程对数据的操作
  • 可见性:当线程修改了数据的状态时,能够立即被其他线程知晓,即数据修改后会立即写入主内存,后续其他线程读取时就能得知数据的变化
    线程安全实质上就是保证在任何调度情况下,同一时刻都只能有一个线程去进行数据操作并将结果写入主存。

如何保证线程安全

  • 在尽可能的情况下,保证mutable类不会共享数据
  • 如果不得不共享数据,最好使用immutable类型
  • 如果不得不共享数据并且使用mutable类型,最好使用线程安全的数据类型
  • 如果以上条件均不能满足,则对必要的操作加锁,加锁的方式主要有两种:使用关键词synchronized或者使用ReentrantLock

synchronized和ReentrantLock的区别

  • 由于synchronized是在JVM层面实现的,因此系统可以监控锁的释放与否;而ReentrantLock是使用代码实现的,系统无法自动释放锁,需要在代码中的finally子句中显式释放锁lock.unlock()
  • 在并发量比较小的情况下,使用synchronized是个不错的选择;但是在并发量比较高的情况下,其性能下降会很严重,此时ReentrantLock是个不错的方案
  • 在使用synchronized 代码块时,可以与wait()、notify()、notifyAll()一起使用,从而进一步实现线程的通信
  • ReentrantLock提供了一些高级功能,如等待可中断,即某线程在等待锁的时候可以放弃等待,转而去处理其他的事情等
  • ReentrantLock中多个线程在等待一个锁时,必须按照申请锁的时间顺序来获得锁。synchronized中的锁是非公平的,释放的一瞬间任何线程都可能获得锁。ReentrantLock默认是非公平的,但可以通过带bool值得构造函数要求使用公平锁。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值