相对于上一节中使用XXX.class粗粒度的锁,可以使用细粒度锁提升性能。
首先转账业务的资源:转出账户,转入账户。需要分别对两个账户加锁。
加锁示意图细粒度锁提升了性能,但是存在死锁问题:比如A、B两个账户,线程1从A向B转账,线程2从B向A转账,线程1获得A的锁,等待B锁;线程2获得B锁,等待A锁,陷入死锁。
出现死锁满足的四个条件:
1.互斥,共享资源 X 和 Y 只能被一个线程占用;
2.占有且等待,线程 T1 已经取得共享资源 X,在等待共享资源 Y 的时候,不释放共享资源 X;
3.不可抢占,其他线程不能强行抢占线程 T1 占有的资源;
4.循环等待,线程 T1 等待线程 T2 占有的资源,线程 T2 等待线程 T1 占有的资源,就是循环等待。
解决死锁的方式:
1.破坏互斥性。使用锁的目的是为了互斥,无法破坏。
2.破坏占有并等待:一次性申请所有的资源。这个例子里,线程所使用的资源是转出账户和转入账户。一次性获取两者的资源。引入一个管理单例对象,负责分配和收回资源。
3.破坏不可抢占条件:java中的synchronized并不能破坏这一条,无法自己释放锁。但是Lock类是可以的
4.。破坏循环等待:给资源排好顺序,按顺序分配资源。
本节问题:破坏占用且等待条件,我们也是锁了所有的账户,而且还是用了死循环 while(!actr.apply(this, target));这个方法,那它比 synchronized(Account.class) 有没有性能优势呢?
问题回答:synchronized(Account.class)锁住的是所有对象,导致只能串行进行;使用单例管理的方式,只锁住操作中涉及的对象,对其他对象没有影响。
网友评论