synchronized与Lock,你真的了解了吗?

线程安全问题一直是我们关注和需要解决的问题。
多个线程的以下三个特性:原子性、可见性、有序性;若任意一个不满足,都存在线程安全问题,那如何解决线程安全的问题呢?
synchronized实现线程安全
(1)同步代码块
synchroinzed(锁的对象) {}
-普通对象(对象锁)
-类.class(类的反射对象)

(1)同步方法
-成员同步方法 锁的是当前对象this
-静态同步方法 锁的是当前类.class
synchronized底层实现(对象的Monitor机制):
任意一个对象都有Monitor,synchronized对象锁实际上就是获取该对象的Monitor。
当前线程要想获取到该锁的Monitor的流程:
先判断锁对象Monitor计数器值是否为0,
为0表示此时Monitor还未被任何线程持有,当前线程获取Monitor,并且将持有线程置为自己,将Monitor的值+1.
不为0表示此时Monitor已经被线程持有,判断持有线程是否是当前线程,若是,Monitor值再次+1;
若持有线程不是当前线程,线程进入阻塞态,直到Monitor的值减为0.

在此引入一个概念:什么是可重入锁呢?
“可重入”顾名思义就是可以再次获取,所以可重入锁指:持有锁的线程再次获取锁。
synchronized就是支持可重入的锁。

JDK1.6关于synchronized的优化
1.CAS(Compare And Swap):比较 和交换
CAS(O,V,N) O:当前线程认为主内存的值 V:主内存中的实际值 N:希望更新的值
(1)当V和O相同时,也就是说旧值和内存中实际的值相同表明该值没有被其他线程更改过,即该旧值O就是目前来说最新的值了,自然而然可以将新值N赋值给V。
(2)V和O不相同,表明该值已经被其他线程改过了则该旧值O不是最新版本的值了,所以不能将新值N赋给V,返回V即可。
当多个线程使用CAS操作一个变量时,只有一个线程会成功,并成功更新,其余会失败。失败的线程会重新尝试(retry),当然也可以选择挂起线程。

2.自旋:处理器上跑无用指令,但是线程不阻塞。
自适应自旋:重量级锁的优化
JVM给一个时间段,在该时间段内,线程是自旋状态,若在该时间段内获取到锁,下一次适当延长自旋时间;否则将线程阻塞,下一次适当缩短自旋时间。
3.锁粗化
将多次连续的加减锁过程粗化为一次大的加减锁过程
4.锁消除
在没有多线程访问的场景下,将锁直接消除。

 public static void main(String[] args) {
         StringBuffer sb = new StringBuffer();
         sb.append("hello");
         sb.append("world");
         sb.append("test");
    }

死锁产生的原因:
1.互斥:共享资源X,Y只能被一个线程占用
2.占有且等待:线程1已经取得共享资源X,同时在等待资源Y,并且不释放X
3.不可抢占:其他线程无法抢占线程1已经占用的资源X
4.循环等待:线程1等待线程2的资源,线程2等待线程1的资源
以上四个条件同时满足才会产生死锁

死锁的现象:程序出现"假死"现象
死锁的解决:破坏以上四个条件中的任意一个条件。

JDK1.5 引入Lock体系来优雅的解决死锁问题
1.Lock的使用格式
try {
lock.lock();
}catch(Exception e){

}finally {
lock.unlock();
}

2.Lock接口的重要方法:
(1)响应中断
void lockInterruptibly() throws InterruptedException;
破坏了不可抢占这个条件
(2)非阻塞式获取锁,若获取锁失败,线程继续执行,不再阻塞
boolean tryLock();
破坏了占有且等待这个条件
(3)支持超时,获取锁失败的线程等待一段时间后若还未获取到锁,线程退出
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

3.Lock的常用子类
ReentrantLock:可重入锁(Lock接口中常用的子类,语义与synchronized基本一致,也是独占锁的实现)
ReentrantReadWriteLock:可重入读写锁
同步对列与等待队列:
同步队列:所有获取锁失败的线程进入同步队列排队获取锁(先进入的先获取锁)
等待队列:调用wait的线程置入等待队列,等待被唤醒(notify),被唤醒后,进入同步对列(尾插式进入)
如图:
在这里插入图片描述
synchronized是一种非公平锁

一.synchronized与ReentrantLock的关系与区别?
1.synchronized与ReentrantLock都属于独占锁的实现,都支持可重入.
2.区别:
(1)synchronized是关键字,JVM层面的实现;ReentrantLock是Java语言层面的实现
(2)ReentrantLock具备一些synchronized不具备的特性,如响应中断、支持超时、支持非阻塞式的获取锁,可以实现公平锁(默认非公平锁).
(3)synchronized只有一个等待队列,而lock调用newCondition()产生多个等待队列。
二.synchronized与Lock的关系与区别
1.synchronized与ReentrantLock都属于独占锁的实现,都支持可重入.
2.区别:
(1).synchronized是关键字,JVM层面的实现;ReentrantLock是Java语言层面的实现,Lock是一个接口
(2).ReentrantLock具备一些synchronized不具备的特性,如响应中断、支持超时、支持非阻塞式的获取锁,可以实现公平锁(默认非公平锁),
可以实现读写锁.
(3)synchronized只有一个等待队列,而lock调用newCondition()产生多个等待队列

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值