目录

  • 一、读写锁的理解
  • 二、读写锁的代码示例
  • 三、多个线程进行读操作的测试案例
  • 四、多个线程进行写操作的测试案例
  • 五、多个线程进行读写操作的测试案例


一、读写锁的理解

  • 读写锁实际维护了一对锁,一个读锁,一个写锁,通过分离读锁和写锁,使得其并发性比独占式锁(排他锁)有了很大的提升。
  • 读锁(共享锁):同一时刻可以允许多个线程访问共享资源。
  • 写锁(排他锁):在写线程访问的时候,所有的读线程和其他写线程都会被阻塞。即如果一个线程想要去写共享资源,就不应该再有其他线程可以对该共享资源进行读或者是写操作了。

二、读写锁的代码示例

package com.xz.thread.t11;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @description: 读写锁代码示例
 * @author: xz
 */
public class Demo {
    //声明一个map,存储数据
    private Map<String,Object> map =new HashMap<>();
    /**
     *    1、ReentrantReadWriteLock实例实现了ReadWriteLock接口
     *    2、声明一个ReentrantReadWriteLock实例,指向父类ReadWriteLock的引用
     *       因为ReentrantReadWriteLock可以保证公平或者非公平
     *    3、ReadWriteLock类中只有readLock()和writeLock() 两个方法
     */
    private ReadWriteLock rwl =new ReentrantReadWriteLock();
    //读锁
    private Lock r =rwl.readLock();
    //写锁
    private Lock w =rwl.writeLock();

    //读操作,即获取数据方法
    public Object get(String key){
        r.lock();//获取读锁
        System.out.println(Thread.currentThread().getName()+"【读】操作正在执行--------");
        try {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return map.get(key);
        }finally {
            r.unlock();//释放读锁
            System.out.println(Thread.currentThread().getName()+"【读】操作执行完毕!!!!!");
        }
    }

    //写操作,即添加或修改数据方法
    public void put(String key,String value){
        w.lock();//获取写锁
        System.out.println(Thread.currentThread().getName()+"【写】操作正在执行========");
        try {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            map.put(key,value);
        }finally {
            w.unlock();//释放写锁
            System.out.println(Thread.currentThread().getName()+"【写】操作执行完毕!!!!!");
        }

    }
}

三、多个线程进行读操作的测试案例

1、代码

package com.xz.thread.t11;

/**
 * @description: 多个线程进行读操作的测试类
 * @author: xz
 */
public class ReadTest {
    public static void main(String[] args) {
        Demo d =new Demo();
        d.put("name","张三");

        //第一个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(d.get("name"));
            }
        }).start();

        //第二个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(d.get("name"));
            }
        }).start();

        //第三个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(d.get("name"));
            }
        }).start();
    }
}

2、输出结果

java 一条线程做多少 java一个线程读一个线程写_System


3、结论

  • 多个线程同时读一个资源类是没有任何问题的,所以为了满足在并发的情况下,读取共享资源是可以同时进行的。

四、多个线程进行写操作的测试案例

1、代码

package com.xz.thread.t11;

/**
 * @description: 多个线程进行写操作的测试类
 * @author: xz
 */
public class WriteTest {
    public static void main(String[] args) {
        Demo d =new Demo();

        //第一个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                d.put("name","张三");
            }
        }).start();

        //第二个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                d.put("name","李四");
            }
        }).start();

        //第三个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                d.put("name","王五");
            }
        }).start();
    }
}

2、输出结果

java 一条线程做多少 java一个线程读一个线程写_读锁_02


3、结论

  • 如果一个线程想要去写共享资源,就不应该再有其他线程可以对该共享资源进行读或者是写操作了。

五、多个线程进行读写操作的测试案例

1、代码

package com.xz.thread.t11;

/**
 * @description: 多个线程进行写操作和读操作的测试类
 * @author: xz
 */
public class WriteReadTest {
    public static void main(String[] args) {
        Demo d =new Demo();

        //第一个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                d.put("name","张三");
            }
        }).start();

        //第二个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                d.get("张三");
            }
        }).start();


    }
}

2、输出结果

java 一条线程做多少 java一个线程读一个线程写_java 一条线程做多少_03


3、结论

  • 在写线程访问的时候,所有的读线程和其他写线程都会被阻塞。