Lock接口在多线程和并发编程中最大的优势是它们分别为读和写提供了锁。

读写锁ReentrantReadWriteLock,它表示有两个锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也叫排他锁。“读写”、“写读”、和 “写写“ 都是互斥的;而 ”读读“ 是异步的,非互斥的。

即:多个线程可以同时进行读取操作,但是同一时刻只允许一个线程进行写入操作。

本题目就可以使用读写锁ReentrantReadWriteLock来实现。

1.读读共享例子

public class Main{
    public static void main(String[] args) {
        Service service = new Service();
        new Thread(new Runnable() {
            @Override
            public void run() {
                service.read();
            }
        },"A").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                service.read();
            }
        },"B").start();
    }
}

class Service{
    // 读写
    ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void read(){
        try{
            // 读锁
            rwLock.readLock().lock();
            System.out.println(Thread.currentThread().getName()+"获得了读锁");
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            System.out.println(Thread.currentThread().getName()+"释放了读锁");
            rwLock.readLock().unlock();
        }
    }
}

2.写写互斥例子

public class Main{
    public static void main(String[] args) {
        Service service = new Service();
        new Thread(new Runnable() {
            @Override
            public void run() {
                service.write();
            }
        },"A").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                service.write();
            }
        },"B").start();
    }
}

class Service{
    // 读写
    ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void write(){
        try{
            // 读锁
            rwLock.writeLock().lock();
            System.out.println(Thread.currentThread().getName()+"获得了写锁");
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            System.out.println(Thread.currentThread().getName()+"释放了写锁");
            rwLock.writeLock().unlock();
        }
    }
}

3.读写互斥例子

public class Main{
    public static void main(String[] args) {
        Service service = new Service();
        new Thread(new Runnable() {
            @Override
            public void run() {
                service.write();
            }
        },"A").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                service.read();
            }
        },"B").start();
    }
}

class Service{
    // 读写
    ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void write(){
        try{
            // 写锁
            rwLock.writeLock().lock();
            System.out.println(Thread.currentThread().getName()+"获得了写锁");
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            System.out.println(Thread.currentThread().getName()+"释放了写锁");
            rwLock.writeLock().unlock();
        }
    }

    public void read(){
        try{
            // 写锁
            rwLock.readLock().lock();
            System.out.println(Thread.currentThread().getName()+"获得了读锁");
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            System.out.println(Thread.currentThread().getName()+"释放了读锁");
            rwLock.readLock().unlock();
        }
    }
}

如果需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,一次来保证它的完整性,该如何实现?代码如下:

public class Main{
    public static void main(String[] args) {
        Cache cache = new Cache();
        // 10个线程读数据
        for (int i = 1; i <= 10; i++) {
            new Thread(()->{
                cache.read();
            },"read"+i).start();
        }

        // 10个线程写数据
        for (int i = 1; i <= 10; i++) {
            String s = i + "";
            new Thread(()->{
                cache.write(s);
            },"write"+i).start();
        }
    }
}

class Cache{
    ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private String data = null;

    public Cache() {
    }

    public void read(){

        try{
            rwLock.readLock().lock();
            System.out.println(Thread.currentThread().getName()+"正在读取数据");
            Thread.sleep(new Random().nextInt(100));
            System.out.println(Thread.currentThread().getName()+"数据读取完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            rwLock.readLock().unlock();
        }
    }

    public void write(String s){

        try{
            rwLock.writeLock().lock();
            System.out.println(Thread.currentThread().getName()+"正在写数据");
            Thread.sleep(new Random().nextInt(100));
            System.out.println(Thread.currentThread().getName()+"数据写完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            rwLock.writeLock().unlock();
        }
    }
}