并发编程之ReadWriteLock接口

18 篇文章 2 订阅

前言

在没有读写锁之前,ReentrantLockSynchronized 虽然可以保证线程安全,但是也浪费了一定的资源

  • 因为如果多个读操作同时进行,其实并没有线程安全问题,可以允许让多个读操作并行,以便提高程序效率
  • 但是写操作不是线程安全的,如果多个线程同时写,或者在写的同时进行读操作,便会造成线程安全问题

我们的 ReadWriteLock 接口就解决了这样的问题,它设定了一套规则,既可以保证多个线程同时读的效率,同时又可以保证有写入操作时的线程安全

整体思路是它有两把锁:一把锁是写锁,获得写锁之后,既可以读数据又可以修改数据,而另一把锁是读锁,获得读锁之后,只能查看数据,不能修改数据。读锁可以被多个线程同时持有,所以多个线程可以同时查看数据。在读的地方合理使用读锁,在写的地方合理使用写锁,灵活控制,可以提高程序的执行效率

ReadWriteLock 接口简介及源码

在这里插入图片描述

ReadWriteLockjava.util.concurrent.locks 包下的接口。ReadWriteLock 管理一组锁,一个是读锁,一个是写锁

  • 读锁是共享的
  • 写锁是独占的
  • 理论上,读写锁比互斥锁( SynchronizedReentrantLock )有更好的性能体现
public interface ReadWriteLock {

    Lock readLock();

    Lock writeLock();
}

所有 ReadWriteLock 接口的实现类必须保证内存同步效果:所有写锁 writeLock 的相关操作都对只读锁 readLock 可见。也就是说,如果一个线程成功的获取了只读锁 readLock,那么这个线程可以看到上个写锁 writeLock 所做的所有修改

ReetrantReadWriteLock

ReentrantReadWriteLock 被称为读写锁,它是 ReadWriteLock 接口的实现

获取顺序

这个类不会强行指定访问锁的读写顺序,但是它支持一个可选的公平策略

非公平模式(默认)

当以非公平模式初始化时,读锁和写锁的获取的顺序是不确定的。非公平锁主张竞争获取,可能会延缓一个或多个读或写线程,但是会比公平锁有更高的吞吐量

公平模式

  • 当以公平模式初始化时,线程将会以队列的顺序获取锁。当前线程释放锁后,等待时间最长的写锁线程就会被分配写锁;或者有一组读线程组等待时间比写线程长,那么这组读线程组将会被分配读锁
  • 当有写线程持有写锁或者有等待的写线程时,一个尝试获取公平的读锁(非重入)的线程就会阻塞。这个线程直到等待时间最长的写锁获得锁后并释放掉锁后才能获取到读锁

支持 Condition

就像 ReentrantLock 一样,写锁支持 Condition 操作。当然,这种 Condition 操作,只能被应用在写锁上。读锁不支持 Condition 操作,readLock().newCondition() 会抛出一个 UnsupportedOperationException 异常

ReentrantReadWriteLock 源码

ReentrantReadWriteLock 主要源码

public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {

	private final ReentrantReadWriteLock.ReadLock readerLock;

    private final ReentrantReadWriteLock.WriteLock writerLock;
    
    final Sync sync;    

    public ReentrantReadWriteLock() {
        this(false);
    }

    public ReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }

	// 实现了接口 ReadWriteLock 的 writeLock() 方法
	public ReentrantReadWriteLock.WriteLock writeLock() { 
		return writerLock; 
	}

	// 实现了接口 ReadWriteLock 的 readLock() 方法
	public ReentrantReadWriteLock.ReadLock readLock()  { 
		return readerLock; 
	}

	// 返回当前线程获取写锁的次数
	public int getWriteHoldCount() {
        return sync.getWriteHoldCount();
    }

	// 返回当前线程获取读锁的次数
	public int getReadHoldCount() {
        return sync.getReadHoldCount();
    }
	
	// 返回当前读锁被获取的次数,但不是占用该锁的线程数,也就是说,一个线程如果 n 次获取该锁,该方法返回 n,而不是 1
	public int getReadLockCount() {
        return sync.getReadLockCount();
    }
	
	// 判断写锁是否被获取
	public boolean isWriteLocked() {
        return sync.isWriteLocked();
    }

	// 静态内部类 ReadLock 
	public static class ReadLock implements Lock, java.io.Serializable {
        private static final long serialVersionUID = -5992448646407690164L;
        private final Sync sync;

        protected ReadLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }
		
		// 实现了接口 Lock 的方法
		public void lock() {
            sync.acquireShared(1);
        }
		
		// 实现了接口 Lock 的方法
        public void lockInterruptibly() throws InterruptedException {
            sync.acquireSharedInterruptibly(1);
        }

		// 实现了接口 Lock 的方法
        public boolean tryLock() {
            return sync.tryReadLock();
        }
		
		// 实现了接口 Lock 的方法
        public boolean tryLock(long timeout, TimeUnit unit)
                throws InterruptedException {
            return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
        }

		// 实现了接口 Lock 的方法
        public void unlock() {
            sync.releaseShared(1);
        }

		// 实现了接口 Lock 的方法
        public Condition newCondition() {
            throw new UnsupportedOperationException();
        }

		// 重写了父类 Object 类的方法
        public String toString() {
            int r = sync.getReadLockCount();
            return super.toString() +
                "[Read locks = " + r + "]";
        }
    }

	// 静态内部类 WriteLock 
	public static class WriteLock implements Lock, java.io.Serializable {
        private static final long serialVersionUID = -4992448646407690164L;
        private final Sync sync;

        protected WriteLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }

        public void lock() {
            sync.acquire(1);
        }
        
        public void lockInterruptibly() throws InterruptedException {
            sync.acquireInterruptibly(1);
        }

        public boolean tryLock( ) {
            return sync.tryWriteLock();
        }

        public boolean tryLock(long timeout, TimeUnit unit)
                throws InterruptedException {
            return sync.tryAcquireNanos(1, unit.toNanos(timeout));
        }

        public void unlock() {
            sync.release(1);
        }
        
        public Condition newCondition() {
            return sync.newCondition();
        }

		// 重写了父类 Object 类的方法
        public String toString() {
            Thread o = sync.getOwner();
            return super.toString() + ((o == null) ?
                                       "[Unlocked]" :
                                       "[Locked by thread " + o.getName() + "]");
        }

        public boolean isHeldByCurrentThread() {
            return sync.isHeldExclusively();
        }

        public int getHoldCount() {
            return sync.getWriteHoldCount();
        }
    }
}    

ReentrantReadWriteLock 获取读锁或写锁的方法

// 实现了接口 ReadWriteLock 的 writeLock() 方法
public ReentrantReadWriteLock.WriteLock writeLock() { 
	return writerLock; 
}

// 实现了接口 ReadWriteLock 的 readLock() 方法
public ReentrantReadWriteLock.ReadLock readLock()  { 
	return readerLock; 
}

ReentrantReadWriteLock 获取与释放锁

读锁的获取

// 拿到 ReentrantReadWriteLock 的实例
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 使用 ReentrantReadWriteLock 的实例,调用自己的 readLock() 方法拿到读锁
Lock readLock = readWriteLock.readLock();

读锁的释放

readLock.unlock();

写锁的获取

// 拿到 ReentrantReadWriteLock 的实例
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 使用 ReentrantReadWriteLock 的实例,调用自己的 writeLock() 方法拿到写锁
Lock writeLock = readWriteLock.writeLock();

写锁的释放

readLock.unlock();

ReetrantReadWriteLock 使用场景

适用于读多写少的场景,在此场景中能发挥它的优势。提高了效率的同时,又可以保证线程的安全

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值