线程同步

1.synchronized
synchronized特点:保证内存可见性、操作原子性
synchronized影响性能的原因:
(1)加锁解锁操作需要额外操作;
(2)互斥同步对性能最大的影响是阻塞的实现,因为阻塞涉及到的挂起线程和恢复线程的操作都需要转入内核态中完成(用户态与内核态的切换的性能代价是比较大的)
2.ReentrantLock
ReentrantLock是java.util.concurrent.locks包中的一个类,是独占锁,为最后一个执行lock操作成功且为释放锁的线程锁拥有.因为它是基于AQS实现的,先看下它和Synchronized的区别
便利性:Synchronized用法更简洁,由编译器去保证锁的加锁和释放; ReenTrantLock需要手动加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。
锁的细粒度和灵活度:ReenTrantLock优于Synchronized
ReenTrantLock特点:
(1)ReenTrantLock可以指定是公平锁还是非公平锁; synchronized只能是非公平锁。
(2)ReenTrantLock提供了一个Condition类,用来实现唤醒特定的线程; synchronized要么随机唤醒一个线程要么唤醒全部线程。
(3) ReenTrantLock提供了一种能够中断等待锁的线程的机制。
3.原子操作类
CAS需要有3个操作数:内存地址V,旧的预期值A,即将要更新的目标值B。
CAS指令执行时,当且仅当内存地址V的值与预期值A相等时,将内存地址V的值修改为B,否则就什么都不做。整个比较并替换的操作是一个原子操作。
CAS的缺点:
CAS虽然很高效的解决了原子操作问题,但是CAS仍然存在三大问题。
(1)循环时间长开销很大。
如果CAS失败,会一直进行尝试。如果CAS长时间一直不成功,可能会给CPU带来很大的开销。
(2)只能保证一个共享变量的原子操作。
当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁来保证原子性。
(3)ABA问题。
如果内存地址V初次读取的值是A,并且在准备赋值的时候检查到它的值仍然为A,那我们就能说它的值没有被其他线程改变过了吗?如果在这段期间它的值曾经被改成了B,后来又被改回为A,那CAS操作就会误认为它从来没有被改变过。这个漏洞称为CAS操作的“ABA”问题。Java并发包为了解决这个问题,提供了一个带有标记的原子引用类“AtomicStampedReference”,它可以通过控制变量值的版本来保证CAS的正确性。因此,在使用CAS前要考虑清楚“ABA”问题是否会影响程序并发的正确性,如果需要解决ABA问题,改用传统的互斥同步可能会比原子类更高效。
4.volatile关键字
(1)volatile用以声明变量的值可能随时会别的线程修改,使用volatile修饰的变量会强制将修改的值立即写入主存,主存中值的更新会使缓存中的值失效(非volatile变量不具备这样的特性,非volatile变量的值会被缓存,线程A更新了这个值,线程B读取这个变量的值时可能读到的并不是是线程A更新后的值)。volatile会禁止指令重排。
(2)volatile特性
volatile具有可见性、有序性,不具备原子性。
可见性:当多个线程访问同一个变量x时,线程1修改了变量x的值,线程1、线程2…线程n能够立即读取到线程1修改后的值
有序性:即程序执行时按照代码书写的先后顺序执行。在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
原子性:原子性通常指多个操作不存在只执行一部分的情况,要不全部执行完毕如果只执行,要不一个都不执行。
(3)volatile适用场景
适用于对变量的写操作不依赖于当前值,对变量的读取操作不依赖于非volatile变量。适用于读多写少的场景。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值