Java 读写锁 ReentrantReadWriteLock

参考

为什么用 ReentrantReadWriteLock

解决线程安全问题使用ReentrantLock就可以了,但是ReentrantLock是独占锁,某一时刻只有一个线程可以获取该锁,而实际中会有写少读多的场景,显然ReentrantLock满足不了这个需求,所以ReentrantReadWriteLock应运而生。ReentrantReadWriteLock采用读写分离的策略,允许多个线程可以同时获取读锁。读写锁——ReentrantReadWriteLock原理详解

锁类型 描述
不加锁 同时可以有多个线程读/写(不安全)
ReentrantLock 同时只可以有一个线程可以读/写
ReentrantReadWriteLock 同时可以多个线程读(共享锁)/同时只有一个线程可以写(独占锁)

代码

错误实现

  1. 代码如下
package thread;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @Author 夏秋初
 * @Date 2022/3/2 10:27
 */
public class Thread5 {
    public static void main(String[] args) {
        Book book = new Book();
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            new Thread(()->{
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                book.write(temp);
            },String.valueOf(i)).start();
        }
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            new Thread(()->{
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                book.read(temp);
            },String.valueOf(i)).start();
        }
    }
}
/**
 * 这样会导致执行时如 write,刚刚开始写入下一步就被别人插队了
 */
class Book{
    private volatile Map<Integer,String> content = new HashMap(5000);
    public void read(int i){
        System.out.println(Thread.currentThread().getName()+"开始读取");
        System.out.println(Thread.currentThread().getName()+content.get(i));
        System.out.println(Thread.currentThread().getName()+"读取完毕");
    }
    public void write(int i){
        System.out.println(Thread.currentThread().getName()+"开始写入");
        content.put(i, "写入成功");
        System.out.println(Thread.currentThread().getName()+"写入完毕");
    }
}
  1. 执行结果
Code(点击打开)

6开始写入
0开始读取
1开始写入
9开始写入
6写入完毕
4开始写入
3开始写入
1开始读取
9写入完毕
5开始写入
5写入完毕
7开始写入
8开始写入
2开始读取
7开始读取
8写入完毕
0开始写入
0写入完毕
8开始读取
5开始读取
7写入完毕
9开始读取
3写入完毕
4写入完毕
1写入完毕
6开始读取
2开始写入
2写入完毕
3开始读取
4开始读取
6写入成功
1写入成功
3写入成功
1读取完毕
4写入成功
4读取完毕
2null
8写入成功
8读取完毕
7写入成功
7读取完毕
0null
0读取完毕
2读取完毕
9写入成功
9读取完毕
5写入成功
5读取完毕
6读取完毕
3读取完毕
进程已结束,退出代码为 0

正确代码

  1. 代码如下
package thread;

import java.awt.print.Book;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @Author 夏秋初
 * @Date 2022/3/2 10:27
 */
public class Thread5 {
    public static void main(String[] args) {
        Book1 book = new Book1();
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            new Thread(()->{
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                book.write(temp);
            },String.valueOf(i)).start();
        }
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            new Thread(()->{
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                book.read(temp);
            },String.valueOf(i)).start();
        }
    }
}
/**
 *
 */
class Book1{
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
    private ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
    private volatile Map<Integer,String> content = new HashMap(5000);
    public void read(int i){
        readLock.lock();
        System.out.println(Thread.currentThread().getName()+"获取读锁完毕");
        try {
            System.out.println(Thread.currentThread().getName()+"开始读取");
//            System.out.println(Thread.currentThread().getName()+content.get(i));
            System.out.println(Thread.currentThread().getName()+"读取完毕");
        }finally {
            System.out.println(Thread.currentThread().getName()+"释放读锁完毕");
            readLock.unlock();
        }


    }
    public void write(int i){
        writeLock.lock();
        System.out.println(Thread.currentThread().getName()+"获取写锁完毕");
        try {
            System.out.println(Thread.currentThread().getName()+"开始写入");
            content.put(i, "写入成功");
            System.out.println(Thread.currentThread().getName()+"写入完毕");
        }finally {
            System.out.println(Thread.currentThread().getName()+"释放写锁完毕");
            writeLock.unlock();
        }
    }
}

  1. 执行结果
Code(点击打开)

4获取写锁完毕
4开始写入
4写入完毕
4释放写锁完毕
6获取写锁完毕
6开始写入
6写入完毕
6释放写锁完毕
1获取写锁完毕
1开始写入
1写入完毕
1释放写锁完毕
9获取写锁完毕
9开始写入
9写入完毕
9释放写锁完毕
2获取写锁完毕
2开始写入
2写入完毕
2释放写锁完毕
7获取写锁完毕
7开始写入
7写入完毕
7释放写锁完毕
0获取写锁完毕
0开始写入
0写入完毕
0释放写锁完毕
3获取写锁完毕
3开始写入
3写入完毕
3释放写锁完毕
8获取写锁完毕
8开始写入
8写入完毕
8释放写锁完毕
8获取读锁完毕
6获取读锁完毕
6开始读取
9获取读锁完毕
9开始读取
9读取完毕
8开始读取
8读取完毕
6读取完毕
6释放读锁完毕
9释放读锁完毕
8释放读锁完毕
5获取写锁完毕
5开始写入
5写入完毕
5释放写锁完毕
7获取读锁完毕
2获取读锁完毕
3获取读锁完毕
1获取读锁完毕
0获取读锁完毕
1开始读取
4获取读锁完毕
3开始读取
5获取读锁完毕
2开始读取
7开始读取
2读取完毕
5开始读取
3读取完毕
4开始读取
1读取完毕
0开始读取
1释放读锁完毕
4读取完毕
3释放读锁完毕
5读取完毕
2释放读锁完毕
7读取完毕
5释放读锁完毕
4释放读锁完毕
0读取完毕
7释放读锁完毕
0释放读锁完毕
进程已结束,退出代码为 0

posted @ 2022-03-02 11:14  夏秋初  阅读(46)  评论(0编辑  收藏  举报