必赢彩票代理直营网:ReentrantReadWriteLock存在原因?


本文地址:http://f83.ib911.com/14883474/2614273
文章摘要:必赢彩票代理直营网,随后看了看自己战斗中去 那就是找到自己父母还想他们帮忙应该也是为了杀我吧异能者与修炼者。

我们知道List的实现类ArrayList,LinkedList都是非线程安全的,Vector类通过用synchronized修饰方法保证了List的多线程非安全问题,但是有个缺点:读写同步,效率低下。于是就出现了CopyOnWriteArrayList,它通过写时复制数组实现了读写分离,提高了多线程对List读的效率,适合多读少些的情况。同理:我们知道ReentrantLock,它是一把独占的锁,是用来控制线程同步的,如果我们用ReentrantLock来实现ArrayList安全,能否达到CopyOnWriteArrayList同样的效果呢?

import?java.util.ArrayList;
import?java.util.List;
import?java.util.concurrent.locks.ReentrantReadWriteLock;

/**
?*?@author?:jiaolian
?*?@date?:Created?in?2021-01-26?15:49
?*?@description:ReentrantReadWriteLock多读少写的场景
?*?@modified?By:
?*?公众号:叫练
?*/
public?class?MultReadTest?{


????private?static?class?MyList?{
????????private?final?ReentrantReadWriteLock?REENTRANT_READ_WRITE_LOCK?=?new?ReentrantReadWriteLock();
????????private?final?ReentrantReadWriteLock.WriteLock?WRITE_LOCK?=?REENTRANT_READ_WRITE_LOCK.writeLock();
????????private?final?ReentrantReadWriteLock.ReadLock?READ_LOCK?=?REENTRANT_READ_WRITE_LOCK.readLock();
????????private?List<String>?list?=?new?ArrayList();

????????//读list
????????public?void?readList()?{
????????????try?{
????????????????READ_LOCK.lock();
????????????????Thread.sleep(1000);
????????????????System.out.println(Thread.currentThread().getName()+":"+list.size());
????????????}?catch?(InterruptedException?e)?{
????????????????e.printStackTrace();
????????????}?finally?{
????????????????READ_LOCK.unlock();
????????????}
????????}

????????//写list
????????public?void?writeList()?{
????????????try?{
????????????????WRITE_LOCK.lock();
????????????????Thread.sleep(1000);
????????????????System.out.println(Thread.currentThread().getName()+":新增1个元素");
????????????????list.add("叫练【公众号】");

????????????}?catch?(InterruptedException?e)?{
????????????????e.printStackTrace();
????????????}?finally?{
????????????????WRITE_LOCK.unlock();
????????????}
????????}

????}

????public?static?void?main(String[]?args)?{
????????MyList?myList?=?new?MyList();
????????//读写锁适合多读少写情况
????????//新建10个读线程,1个写线程
????????new?Thread(()->{myList.writeList();},"写线程").start();
????????for?(int?i=0;?i<10;?i++)?{
????????????new?Thread(()->{myList.readList();},"读线程"+(i+1)).start();
????????}
????}

}

上面案例我们用ReentrantReadWriteLock实现了CopyOnWriteArrayList,主线程新建了1个写线程写list,10个读线程读list,程序一共花费2执行完毕,如果用Vector需要花费11秒。在多线程的情况下,通过读写锁操作List,提高了List的读效率,在List读的部分,线程是共享的,在对List写的过程中,在对写的线程是同步的,因此我们可以得出一个结论:读写锁是读读共享,读写同步



独占获取锁简单流程


如上图,我们简单的梳理下共享锁获取锁流程。

  1. 独占锁获取(上述例子中的READ_LOCK读锁),首先判断是否有线程获取了锁。
  2. 有读锁:当前线程发现此时读锁状态被占用,说明有线程获取了读锁。该线程通过cas自旋【死循环】获取到读锁为止。
  3. 有写锁:还需要判断持有写锁的线程是否是自己,如果是自己而且此时是获取的是读锁会获取锁成功,我们称为锁降级,如果不是自己说明此时有其他线程获取了写锁,那么当前线程需要排队阻塞。
  4. 无锁:直接获取锁。


写锁降级


我们说读写互斥,但同一个线程中,先写后读也是允许的,我们称之为锁降级。在面试中共享锁面试频率也比较高,方便理解我们举个简单的案例说明下。

import?java.util.concurrent.locks.ReentrantReadWriteLock;

/**
?*?@author?:jiaolian
?*?@date?:Created?in?2021-01-28?15:44
?*?@description:ReentrantReadWriteLock读写锁降级测试
?*?@modified?By:
?*?公众号:叫练
?*/
public?class?WriteLockLowerTest?{

????private?static?final?ReentrantReadWriteLock?REENTRANT_READ_WRITE_LOCK?=?new?ReentrantReadWriteLock();
????private?static?final?ReentrantReadWriteLock.WriteLock?WRITE_LOCK?=?REENTRANT_READ_WRITE_LOCK.writeLock();
????private?static?final?ReentrantReadWriteLock.ReadLock?READ_LOCK?=?REENTRANT_READ_WRITE_LOCK.readLock();

????public?static?void?main(String[]?args)?{
????????try?{
????????????WRITE_LOCK.lock();
????????????System.out.println("获取写锁");
????????????READ_LOCK.lock();
????????????System.out.println("获取读锁");
????????}?finally?{
????????????READ_LOCK.unlock();
????????????System.out.println("释放写锁");
????????????WRITE_LOCK.unlock();
????????????System.out.println("释放读锁");
????????}
????}
}

如上述代码:程序可以运行完毕,说明锁可以降级。另外说一句,上面的程序先获取读锁再获取写锁,程序是会阻塞的,为什么呢?欢迎小伙伴在留言区写下评论!



总结


今天我们用通俗易懂的文字描述了ReentrantReadWriteLock读写锁。喜欢的请点赞加评论哦!点关注,不迷路,我是叫练【公众号】,边叫边练。期待我们下次再见!