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

读写锁


锁机制引入了读写锁特性: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:退出

可以看到:

  1. 进行写操作加锁时,必须等待所有的读操作锁释放。
  2. 写操作加锁后,其他读操作必须等待写操作锁释放之后,才能再进行读操作加锁。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值