Java_并发线程_Lock、ReadWriteLock

1.Lock

ReentrantLock是Lock接口的实现类,使用Lock应该接合线程来使用。如果lock锁没有被其它的线程占用,则当前线程可以立即获得lock锁。同一个线程可在lock锁未释放之前,调用lock多次,使用getHoldCount()得到当前线程lock锁的次数。isHeldByCurrentThread()则判断当前线程是否拥有lock锁。

(1).使用格式

一定要在finally中调用lock.unlock()解锁,防止死锁。
Lock l = ...;
l.lock();
try {
	// access the resource protected by this lock
finally {
	l.unlock();
}}

(2).常用方法

1).void lock();   

尝试获得lock锁,如果锁被别的线程持有,则当前线程不在执行,也不能被调度,直到拿到锁为止;

2).void lockInterruptibly() throws InterruptedException

尝试获取锁,如果锁可以获取,那么立刻返回。如果无非获取锁,那么线程停止执行,并且不能被再调度,直到当前线程被interrupt,则抛出异常;

3).boolean tryLock()

尝试获得锁,如果成功那么锁住对象然后返回true,否则返回false,这个方法会立即返回;

4).boolean tryLock(long time, TimeUnit unit) throws InterruptedException

tryLock类似,等待最大时间内试图获得锁;

5).unlock()

释放锁,减一

6).newCondition()

参考Java_并发线程_Condition一文

(3).与synchronized的区别

synchronized锁的释放是语言内置的,不会出现忘记释放锁的情况,另外由于是语言内置的支持,调试是能很快知道锁被哪个线程持有,它加锁的次数。而Lock只是一个普通的类,所以调试器并不知道这个锁的任何信息,它只是一个普通的对象(当然你可以仔细观察每个线程的stack frame来看它在等待锁),但是Lock更加的灵活具有扩展性。
所以建议:如果只是为了实现互斥,那么使用synchronized,如果想用Lock附加的功能,那么才使用Lock。

2.ReadWriteLock

ReentrantReadWriteLock是ReadWriteLock接口的实现类,接合线程使用。

(1).读锁和写锁条件

1).不同一线程

读锁不互斥,读锁与写锁互斥,写锁与写锁互斥。

2).同一线程

读锁可以获得多次getReadHoldCount(),写锁可以获得多次getWriteHoldCount;

读锁下不能获得写锁,但是写锁下可以提前获得读锁。

(2).格式

class CachedData {
	Object data;
	volatile boolean cacheValid;
	final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

	void processCachedData() {
		rwl.readLock().lock();
		if (!cacheValid) {
			// Must release read lock before acquiring write lock
			rwl.readLock().unlock();
			rwl.writeLock().lock();
			try {
				// Recheck state because another thread might have
				// acquired write lock and changed state before we did.
				if (!cacheValid) {
					// data = ...
					cacheValid = true;

					// Downgrade by acquiring read lock before releasing
					// write lock
					rwl.readLock().lock();
				}
			} finally {
				rwl.writeLock().unlock(); // Unlock write, still hold read
			}
		}

		try {
			// use(data);
		} finally {
			rwl.readLock().unlock();
		}
	}
}

(3).使用注意

读锁是排写锁操作的,读锁不排读锁操作,多个读锁可以并发不阻塞。即在读锁获取后和读锁释放之前,写锁并不能被任何线程获得,

多个读锁同时作用期间,试图获取写锁的线程都处于等待状态,当最后一个读锁释放后,试图获取写锁的线程才有机会获取写锁。

写锁是排写锁、排读锁操作的。当一个线程获取到写锁之后,其他试图获取写锁和试图获取读锁的线程都处于等待状态,直到写锁被释放。

写锁是可以获得读锁的,即:

rwl.writeLock().lock();
//在写锁状态中,可以获取读锁
rwl.readLock().lock();
rwl.writeLock().unlock();
读锁是不能够获得写锁的,如果要加写锁,本线程必须释放所持有的读锁,即:

rwl.readLock().lock();
//......
//必须释放掉读锁,才能够加写锁
rwl.readLock().unlock();
rwl.writeLock().lock();

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。