Java并发程序设计(15)并发锁之读写锁(续二)写锁降级
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java并发程序设计(15)并发锁之读写锁(续二)写锁降级相关的知识,希望对你有一定的参考价值。
1.1.1. 读写锁应用之三写锁降级
ReentrantReadWriteLock还具有写锁降级的特点,而这跟可重入性有一些关系。
(1)持有写锁时可以降级为读锁。
(2)持有读锁时不能升级为写锁。
ReentrantReadWriteLock和ReentrantLock相似的是都有一个特点,就是可重入。可重入指已经获取到锁的线程可以再次获取锁,保证lock和unlock的次数相同即可。
package com.test.concurrence; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; class MySharedResource3 { //构造函数:公平锁。 private ReadWriteLock lock = new ReentrantReadWriteLock(true); public void read(int taskid){ lock.readLock().lock(); try{ for(int i=0;i<10;i++){ x--; System.out.println(taskid + "," + i + ": read called: x:" + x + " , "+ Thread.currentThread().getName()); Thread.sleep(100); } } catch (InterruptedException e) { e.printStackTrace(); } finally{ lock.readLock().unlock(); } } public void downgrade(int taskid){ //持有写锁 lock.writeLock().lock(); System.out.println(taskid + " writeLock locked."); try{ for(int i=0;i<10;i++){ x++; System.out.println(taskid + "," + i + ": write called: x:" + x + " , "+ Thread.currentThread().getName()); Thread.sleep(100); } //在已经持有写锁的情况下继续持有读锁。 lock.readLock().lock(); System.out.println(taskid + " writeLock -> readLock locked."); //释放写锁后,降级为读锁。 lock.writeLock().unlock(); System.out.println(taskid + " writeLock unlocked."); for(int i=0;i<10;i++){ x++; System.out.println(taskid + "," + i + ": read in write: x:" + x + " , "+ Thread.currentThread().getName()); Thread.sleep(1000); } //释放读锁。 lock.readLock().unlock(); System.out.println(taskid + " readLock locked."); } catch (InterruptedException e) { e.printStackTrace(); } finally{//释放锁。 lock.readLock().lock(); lock.writeLock().unlock(); } } private int x = 0; } public class ReadWriteLockTest3 { public static void main(String[] args) { final MySharedResource3 sr = new MySharedResource3(); ExecutorService executorService = Executors.newCachedThreadPool(); int i; for( i=0;i<10;i++) { final int taskid = i; executorService.execute(new Runnable(){ @Override public void run() { System.out.println("taskid:" + taskid); while(true){ if( 0 == (taskid % 2)){ sr.downgrade(taskid); } else { sr.read(taskid); } } } }); } executorService.shutdown(); } }
观察运行结果,可以看到在downgrade()函数中,当线程在执行写锁已经降级为读锁后的代码块时,其它线程时可以获得读锁的。
一个可能的运行结果如下:
taskid:0
taskid:4
taskid:3
taskid:1
taskid:2
0 writeLock locked.
taskid:5
0,0: write called: x:1 , pool-1-thread-1
taskid:6
taskid:9
taskid:8
taskid:7
0,1: write called: x:2 , pool-1-thread-1
0,2: write called: x:3 , pool-1-thread-1
0,3: write called: x:4 , pool-1-thread-1
0,4: write called: x:5 , pool-1-thread-1
0,5: write called: x:6 , pool-1-thread-1
0,6: write called: x:7 , pool-1-thread-1
0,7: write called: x:8 , pool-1-thread-1
0,8: write called: x:9 , pool-1-thread-1
0,9: write called: x:10 , pool-1-thread-1
0 writeLock -> readLock locked.
0 writeLock unlocked.
0,0: read in write: x:11 , pool-1-thread-1
3,0: read called: x:10 , pool-1-thread-4
3,1: read called: x:9 , pool-1-thread-4
3,2: read called: x:8 , pool-1-thread-4
3,3: read called: x:7 , pool-1-thread-4
3,4: read called: x:6 , pool-1-thread-4
3,5: read called: x:5 , pool-1-thread-4
3,6: read called: x:4 , pool-1-thread-4
3,7: read called: x:3 , pool-1-thread-4
3,8: read called: x:2 , pool-1-thread-4
3,9: read called: x:1 , pool-1-thread-4
0,1: read in write: x:2 , pool-1-thread-1
0,2: read in write: x:3 , pool-1-thread-1
0,3: read in write: x:4 , pool-1-thread-1
0,4: read in write: x:5 , pool-1-thread-1
0,5: read in write: x:6 , pool-1-thread-1
0,6: read in write: x:7 , pool-1-thread-1
0,7: read in write: x:8 , pool-1-thread-1
0,8: read in write: x:9 , pool-1-thread-1
0,9: read in write: x:10 , pool-1-thread-1
0 readLock locked.
4 writeLock locked.
4,0: write called: x:11 , pool-1-thread-5
4,1: write called: x:12 , pool-1-thread-5
4,2: write called: x:13 , pool-1-thread-5
4,3: write called: x:14 , pool-1-thread-5
4,4: write called: x:15 , pool-1-thread-5
4,5: write called: x:16 , pool-1-thread-5
4,6: write called: x:17 , pool-1-thread-5
4,7: write called: x:18 , pool-1-thread-5
4,8: write called: x:19 , pool-1-thread-5
4,9: write called: x:20 , pool-1-thread-5
4 writeLock -> readLock locked.
4 writeLock unlocked.
1,0: read called: x:19 , pool-1-thread-2
4,0: read in write: x:20 , pool-1-thread-5
1,1: read called: x:19 , pool-1-thread-2
1,2: read called: x:18 , pool-1-thread-2
1,3: read called: x:17 , pool-1-thread-2
1,4: read called: x:16 , pool-1-thread-2
1,5: read called: x:15 , pool-1-thread-2
1,6: read called: x:14 , pool-1-thread-2
1,7: read called: x:13 , pool-1-thread-2
1,8: read called: x:12 , pool-1-thread-2
1,9: read called: x:11 , pool-1-thread-2
4,1: read in write: x:12 , pool-1-thread-5
4,2: read in write: x:13 , pool-1-thread-5
4,3: read in write: x:14 , pool-1-thread-5
4,4: read in write: x:15 , pool-1-thread-5
4,5: read in write: x:16 , pool-1-thread-5
4,6: read in write: x:17 , pool-1-thread-5
4,7: read in write: x:18 , pool-1-thread-5
4,8: read in write: x:19 , pool-1-thread-5
4,9: read in write: x:20 , pool-1-thread-5
4 readLock locked.
2 writeLock locked.
2,0: write called: x:21 , pool-1-thread-3
2,1: write called: x:22 , pool-1-thread-3
2,2: write called: x:23 , pool-1-thread-3
2,3: write called: x:24 , pool-1-thread-3
2,4: write called: x:25 , pool-1-thread-3
2,5: write called: x:26 , pool-1-thread-3
2,6: write called: x:27 , pool-1-thread-3
2,7: write called: x:28 , pool-1-thread-3
2,8: write called: x:29 , pool-1-thread-3
2,9: write called: x:30 , pool-1-thread-3
2 writeLock -> readLock locked.
2 writeLock unlocked.
5,0: read called: x:29 , pool-1-thread-6
2,0: read in write: x:30 , pool-1-thread-3
5,1: read called: x:29 , pool-1-thread-6
5,2: read called: x:28 , pool-1-thread-6
5,3: read called: x:27 , pool-1-thread-6
5,4: read called: x:26 , pool-1-thread-6
5,5: read called: x:25 , pool-1-thread-6
5,6: read called: x:24 , pool-1-thread-6
5,7: read called: x:23 , pool-1-thread-6
5,8: read called: x:22 , pool-1-thread-6
5,9: read called: x:21 , pool-1-thread-6
2,1: read in write: x:22 , pool-1-thread-3
2,2: read in write: x:23 , pool-1-thread-3
2,3: read in write: x:24 , pool-1-thread-3
2,4: read in write: x:25 , pool-1-thread-3
2,5: read in write: x:26 , pool-1-thread-3
2,6: read in write: x:27 , pool-1-thread-3
2,7: read in write: x:28 , pool-1-thread-3
2,8: read in write: x:29 , pool-1-thread-3
2,9: read in write: x:30 , pool-1-thread-3
2 readLock locked.
6 writeLock locked.
6,0: write called: x:31 , pool-1-thread-7
6,1: write called: x:32 , pool-1-thread-7
6,2: write called: x:33 , pool-1-thread-7
6,3: write called: x:34 , pool-1-thread-7
6,4: write called: x:35 , pool-1-thread-7
6,5: write called: x:36 , pool-1-thread-7
6,6: write called: x:37 , pool-1-thread-7
6,7: write called: x:38 , pool-1-thread-7
6,8: write called: x:39 , pool-1-thread-7
6,9: write called: x:40 , pool-1-thread-7
6 writeLock -> readLock locked.
6 writeLock unlocked.
6,0: read in write: x:41 , pool-1-thread-7
9,0: read called: x:40 , pool-1-thread-10
9,1: read called: x:39 , pool-1-thread-10
9,2: read called: x:38 , pool-1-thread-10
9,3: read called: x:37 , pool-1-thread-10
9,4: read called: x:36 , pool-1-thread-10
9,5: read called: x:35 , pool-1-thread-10
9,6: read called: x:34 , pool-1-thread-10
9,7: read called: x:33 , pool-1-thread-10
9,8: read called: x:32 , pool-1-thread-10
9,9: read called: x:31 , pool-1-thread-10
6,1: read in write: x:32 , pool-1-thread-7
6,2: read in write: x:33 , pool-1-thread-7
6,3: read in write: x:34 , pool-1-thread-7
6,4: read in write: x:35 , pool-1-thread-7
6,5: read in write: x:36 , pool-1-thread-7
api doc中关于可重入和降级是这么的。
Reentrancy
This lock allows both readers and writers to reacquire read or write locks in the style of a ReentrantLock. Non-reentrant readers are not allowed until all write locks held by the writing thread have been released.
Additionally, a writer can acquire the read lock, but not vice-versa. Among other applications, reentrancy can be useful when write locks are held during calls or callbacks to methods that perform reads under read locks. If a reader tries to acquire the write lock it will never succeed.
【中文】
可重入性
这种锁(ReentrantReadWriteLock)允许读线程和写线程按照ReentrantLock的式样来再次获取到读或写锁。非重入的读是不允许的,直到所有已经被写线程持有的写锁都被 释放了。
另外,写线程能够获取到读锁,但是反过来不行。在其他应用中,调用或回调方法中需要持有读锁时执行读操作时,在已经持有写锁的情况下,可重入性是有用的。如果读线程尝试获取写锁,将不会成功。
Lock downgrading
Reentrancy also allows downgrading from the write lock to a read lock, by acquiring the write lock, then the read lock and then releasing the write lock. However, upgrading from a read lock to the write lock is not possible.
【中文】
锁降级
通过依次获取写锁,获取读锁,然后释放写锁的方式,可重入性也允许从一个写锁降级为一个读锁。然而,从一个读锁升级到写锁是不可能的。
以上是关于Java并发程序设计(15)并发锁之读写锁(续二)写锁降级的主要内容,如果未能解决你的问题,请参考以下文章
Java并发程序设计(20)并发锁之倒数锁CountDownLatch
Java并发程序设计(12)并发锁之可重入锁ReentrantLock