您的位置:首页 > 其它

2.4.线程的同步和协作_读写锁

2014-04-23 12:14 183 查看

读写锁

锁机制引入了读写锁特性:ReadWriteLock接口和唯一的实现类ReentrantReadWriteLock。读写锁是锁机制的最大改进之一,提供了将读和写分开处理的能力。ReentrantReadWriteLock有两个锁,一个是读操作锁,另一个是写操作锁。读操作锁允许多个线程同时访问,但是写操作锁只允许一个线程进行访问,在一个线程执行写操作时,其他线程不能执行读操作。在进行写操作加锁时,必须等待所有的读操作锁都释放之后才能实施写操作加锁。

我们依然以计数器的例子来说明ReadWriteLock的用法,假设只有一个线程更新计数器的值,通过ReadWriteLock的writeLock方法取得写操作锁,进行写操作的同步;其他线程都是读取计数器的值用来显示,通过ReadWriteLock的readLock方法取得读操作锁,进行读操作的同步。示例代码如下:

public class ReadWriteCountDemo {

public static void main(String[] args){
ReadWriteCounter counter = new ReadWriteCounter();
CountReader reader = new CountReader(counter);
CountWriter writer = new CountWriter(counter);

System.out.println("main:创建读写线程");
Thread r1 = new Thread(reader);
Thread r2 = new Thread(reader);
Thread r3 = new Thread(reader);
Thread w = new Thread(writer);

System.out.println("main:启动读写线程");
w.start();
r1.start();
r2.start();
r3.start();

System.out.println("main:等待读写线程");
try {
w.join();
r1.join();
r2.join();
r3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("main:退出");
}
}

class CountReader implements Runnable{

ReadWriteCounter counter = null;

CountReader(ReadWriteCounter counter){
this.counter = counter;
}

@Override
public void run() {
for(int i=0 ;i<5; i++){

long value = counter.get();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}

}
}
}

class CountWriter implements  Runnable{

ReadWriteCounter counter = null;

CountWriter(ReadWriteCounter counter){
this.counter = counter;
}
@Override
public void run() {
for(int i=0; i<5; i++){

counter.increase();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

}

}
}

class ReadWriteCounter{
private long count = 0;
private ReadWriteLock lock = new ReentrantReadWriteLock();

public void increase(){
System.out.println("写操作:申请写操作锁");
lock.writeLock().lock();
System.out.println("写操作:获得写操作锁");
count++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("写操作:完成更新计数器。计数器值:" + count + ",释放写操作锁");
lock.writeLock().unlock();
}

}

public long get(){
System.out.println(Thread.currentThread().getName() + ":读操作:申请读操作锁");
lock.readLock().lock();
System.out.println(Thread.currentThread().getName() + ":读操作:获得读操作锁");
long tmp = count;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName() + ":读操作:计数器值" + tmp + ",释放读操作锁");
lock.readLock().unlock();
}

return tmp;
}
}


程序执行日志:

main:创建读写线程
main:启动读写线程
写操作:申请写操作锁
写操作:获得写操作锁
main:等待读写线程
Thread-1:读操作:申请读操作锁
Thread-2:读操作:申请读操作锁
Thread-0:读操作:申请读操作锁
写操作:完成更新计数器。计数器值:1,释放写操作锁
Thread-1:读操作:获得读操作锁
Thread-2:读操作:获得读操作锁
Thread-0:读操作:获得读操作锁
写操作:申请写操作锁
Thread-0:读操作:计数器值1,释放读操作锁
Thread-2:读操作:计数器值1,释放读操作锁
Thread-1:读操作:计数器值1,释放读操作锁
写操作:获得写操作锁
Thread-0:读操作:申请读操作锁
Thread-2:读操作:申请读操作锁
Thread-1:读操作:申请读操作锁
写操作:完成更新计数器。计数器值:2,释放写操作锁
Thread-0:读操作:获得读操作锁
Thread-2:读操作:获得读操作锁
Thread-1:读操作:获得读操作锁
写操作:申请写操作锁
Thread-2:读操作:计数器值2,释放读操作锁
Thread-1:读操作:计数器值2,释放读操作锁
Thread-0:读操作:计数器值2,释放读操作锁
写操作:获得写操作锁
Thread-2:读操作:申请读操作锁
Thread-0:读操作:申请读操作锁
Thread-1:读操作:申请读操作锁
写操作:完成更新计数器。计数器值:3,释放写操作锁
Thread-2:读操作:获得读操作锁
Thread-0:读操作:获得读操作锁
Thread-1:读操作:获得读操作锁
Thread-0:读操作:计数器值3,释放读操作锁
Thread-2:读操作:计数器值3,释放读操作锁
写操作:申请写操作锁
Thread-1:读操作:计数器值3,释放读操作锁
写操作:获得写操作锁
Thread-2:读操作:申请读操作锁
Thread-1:读操作:申请读操作锁
Thread-0:读操作:申请读操作锁
写操作:完成更新计数器。计数器值:4,释放写操作锁
Thread-2:读操作:获得读操作锁
Thread-1:读操作:获得读操作锁
Thread-0:读操作:获得读操作锁
Thread-2:读操作:计数器值4,释放读操作锁
写操作:申请写操作锁
Thread-0:读操作:计数器值4,释放读操作锁
Thread-1:读操作:计数器值4,释放读操作锁
写操作:获得写操作锁
Thread-1:读操作:申请读操作锁
Thread-2:读操作:申请读操作锁
Thread-0:读操作:申请读操作锁
写操作:完成更新计数器。计数器值:5,释放写操作锁
Thread-1:读操作:获得读操作锁
Thread-0:读操作:获得读操作锁
Thread-2:读操作:获得读操作锁
Thread-0:读操作:计数器值5,释放读操作锁
Thread-2:读操作:计数器值5,释放读操作锁
Thread-1:读操作:计数器值5,释放读操作锁
main:退出


可以看到:

进行写操作加锁时,必须等待所有的读操作锁释放。
写操作加锁后,其他读操作必须等待写操作锁释放之后,才能再进行读操作加锁。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: