Java并行编程时经常使用关键字synchronized来实现同步访问,但是很多情况下synchronized会影响执行效率
例如:当多线程读写文件时,读操作之间并不冲突,但是synchronized会使所有的读操作都同步执行而影响效率
这种情况下最好的解决方法是使用java.util.concurrent.locks下提供的读写锁ReentrantReadWriteLock。这个lock类的读锁是可重入的,只有当有线程获取写锁时才会同步线程
为了学习ReentrantReadWriteLock的使用,写了一个测试类TestMap。通过对静态私有变量map进行get/put操作,测试读写锁的使用。
public class TestMap {
private static final Map<String, String> map;
private static final ReentrantReadWriteLock readWriteLock;
static {
map = new HashMap<String, String>();
readWriteLock = new ReentrantReadWriteLock();
}
public static String get(String key) {
try {
// 读取时使用读锁
readWriteLock.readLock().lock();
System.out.println(Thread.currentThread().getId()
+ " get read lock.");
if (map.containsKey(key)) {
return map.get(key);
}
return "";
} finally {
readWriteLock.readLock().unlock();
System.out.println(Thread.currentThread().getId()
+ " release read lock.");
}
}
public static void set(String key, String value) {
try {
// 写入时使用写锁
readWriteLock.writeLock().lock();
System.out.println(Thread.currentThread().getId()
+ " get write lock.");
map.put(key, value);
} finally {
readWriteLock.writeLock().unlock();
System.out.println(Thread.currentThread().getId()
+ " release write lock.");
}
}
}
要注意锁的释放一定要写在finally代码块中。因为与synchronized不同,发生异常时锁并不会自动被释放
以下是调用TestMap进行测试的代码
public class MapRunable implements Runnable {
@Override
public void run() {
TestMap.set(String.valueOf(Thread.currentThread().getId()), Thread
.currentThread().getName());
TestMap.get(String.valueOf(Thread.currentThread().getId()));
}
}
public static void main(String[] args){
Thread thread1 = new Thread(new MapRunable());
Thread thread2 = new Thread(new MapRunable());
Thread thread3 = new Thread(new MapRunable());
Thread thread4 = new Thread(new MapRunable());
Thread thread5 = new Thread(new MapRunable());
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
}
执行结果为:
9 get write lock.
9 release write lock.
13 get write lock.
13 release write lock.
10 get write lock.
10 release write lock.
12 get write lock.
12 release write lock.
11 get write lock.
11 release write lock.
9 get read lock.
10 get read lock.
10 release read lock.
11 get read lock.
11 release read lock.
12 get read lock.
13 get read lock.
12 release read lock.
9 release read lock.
13 release read lock.
可以看出,当获得写锁时,只能等待该线程将写锁释放。但是获得读锁时,别的线程仍然可以获得读锁。
如果读操作也需要同步,则需要使用ReentrantLock
关于锁tryLock,lockInterruptibly的使用此处不再赘述了
推荐一篇学习过的文章,有比较详细的说明:http://www.cnblogs.com/dolphin0520/p/3923167.html