0%

读写锁

前言

调试JDBC反序列化的时候,里面有这种操作,有点好奇就来看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static ConnectionUrl getConnectionUrlInstance(String connString, Properties info) {
if (connString == null) {
throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("ConnectionString.0"));
}
String connStringCacheKey = buildConnectionStringCacheKey(connString, info);
ConnectionUrl connectionUrl;

rwLock.readLock().lock();
connectionUrl = connectionUrlCache.get(connStringCacheKey);
if (connectionUrl == null) {
rwLock.readLock().unlock();
rwLock.writeLock().lock();
try {
// Check again, in the meantime it could have been cached by another thread.
connectionUrl = connectionUrlCache.get(connStringCacheKey);
if (connectionUrl == null) {
ConnectionUrlParser connStrParser = ConnectionUrlParser.parseConnectionString(connString);
connectionUrl = Type.getConnectionUrlInstance(connStrParser, info);
connectionUrlCache.put(connStringCacheKey, connectionUrl);
}
rwLock.readLock().lock();
} finally {
rwLock.writeLock().unlock();
}
}
rwLock.readLock().unlock();
return connectionUrl;
}

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package org.example;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockTest {

private double data = 0;

ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private ReentrantLock lock = new ReentrantLock();

public void get(){
try {
rwl.readLock().lock();
System.out.println("----Thread:"+Thread.currentThread().getName()+"----read first value:"+data);
Thread.sleep(1000);
System.out.println("----Thread:"+Thread.currentThread().getName()+"----read second value:"+data);
rwl.readLock().unlock();
} catch (Exception e) {
// TODO: handle exception
}
}


public void put(){
try {
rwl.writeLock().lock();
data = Math.random();
System.out.println("----Thread:"+Thread.currentThread().getName()+"----write first value:"+data);
Thread.sleep(100);
rwl.writeLock().unlock();
} catch (Exception e) {
// TODO: handle exception
}
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package org.example;

public class MainReadWritLockTest {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
final ReadWriteLockTest rwlt = new ReadWriteLockTest();
for(int i=0; i<5;i++){
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
rwlt.get();
}
}).start();
}
for(int i=0; i<2;i++){
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
rwlt.put();
}
}).start();
}
}

}

输出结果

1
2
3
4
5
6
7
8
9
10
11
12
----Thread:Thread-0----read first value:0.0
----Thread:Thread-3----read first value:0.0
----Thread:Thread-4----read first value:0.0
----Thread:Thread-2----read first value:0.0
----Thread:Thread-1----read first value:0.0
----Thread:Thread-4----read second value:0.0
----Thread:Thread-1----read second value:0.0
----Thread:Thread-0----read second value:0.0
----Thread:Thread-2----read second value:0.0
----Thread:Thread-3----read second value:0.0
----Thread:Thread-5----write first value:0.38882443875894124
----Thread:Thread-6----write first value:0.537279172993168

可以看到,在read second value这一段结束了,才开始write的操作,也就是说在没有释放readlock的时候,writelock是锁着的,也就是 读读不互斥,写写不互斥,读写有互斥
如果把锁注释,也就是下面的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package org.example;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockTest {

private double data = 0;

ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private ReentrantLock lock = new ReentrantLock();

public void get(){
try {
System.out.println("----Thread:"+Thread.currentThread().getName()+"----read first value:"+data);
Thread.sleep(1000);
System.out.println("----Thread:"+Thread.currentThread().getName()+"----read second value:"+data);
} catch (Exception e) {
// TODO: handle exception
}
}


public void put(){
try {
data = Math.random();
System.out.println("----Thread:"+Thread.currentThread().getName()+"----write first value:"+data);
Thread.sleep(100);
} catch (Exception e) {
// TODO: handle exception
}
}

}

结果如下
1
2
3
4
5
6
7
8
9
10
11
12
----Thread:Thread-2----read first value:0.0
----Thread:Thread-3----read first value:0.0
----Thread:Thread-0----read first value:0.0
----Thread:Thread-1----read first value:0.0
----Thread:Thread-4----read first value:0.0
----Thread:Thread-5----write first value:0.7311360215541859
----Thread:Thread-6----write first value:0.32755079667745735
----Thread:Thread-0----read second value:0.32755079667745735
----Thread:Thread-1----read second value:0.32755079667745735
----Thread:Thread-3----read second value:0.32755079667745735
----Thread:Thread-2----read second value:0.32755079667745735
----Thread:Thread-4----read second value:0.32755079667745735

可以看到write写到中间了

getConnectionUrlInstance

回到开头的代码,可以发现这里是在读取缓存的时候加锁,读完了就释放,然后在加上写锁,往缓存列表放入URL