首先是没有读写锁的代码,定义了一个资源类,里面底层数据结构为HashMap,之后多个线程对其写以及读操作
package com.yuxue.juc.lockDemo; import java.util.HashMap; import java.util.Map; class MyCache { //定义缓存当中的数据结构为Map型,键为String,值为Object类型 private volatile Map<String, Object> map = new HashMap<>(); //向Map中添加元素的方法 public void setMap(String key, Object value) { Thread thread = Thread.currentThread(); System.out.println(thread.getName() + "\t" + " put value:" + value); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } //底层的map直接put map.put(key, value); System.out.println(thread.getName() + "\t" + "put value successful"); } //向Map中取出元素 public void getMap(String key) { Thread thread = Thread.currentThread(); System.out.println(thread.getName() + "\t" + "get the value"); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } //底层的map直接get,并且返回值为Object类型 Object retValue = map.get(key); System.out.println(thread.getName() + "\t" + "get the value successful, is " + retValue); } } /** * 多个线程同时读一个资源类没有任何问题,所以为了满足并发量,读取共享资源应该可以同时进行。 * 但是 * 如果有一个线程想取写共享资源来,就不应该允许其他线程可以对资源进行读或写 * 总结 * 读读能共存 * 读写不能共存 * 写写不能共存 */ public class ReadWriteLockDemo { public static void main(String[] args) { //创建资源类 MyCache myCache = new MyCache(); //创建5个线程 for (int i = 0; i < 5; i++) { //lambda表达的特殊性,需要final变量 final int tempInt = i; new Thread(() -> { //5个线程分别填值 myCache.setMap(tempInt + "", tempInt + ""); }, "thread-" + i).start(); } //创建5个线程 for (int i = 0; i < 5; i++) { final int tempInt = i; new Thread(() -> { //5个线程取值 myCache.getMap(tempInt + ""); }, "thread-" + i).start(); } } }结果为:
thread-0 put value:0 thread-1 put value:1 thread-2 put value:2 thread-3 put value:3 thread-4 put value:4 thread-0 get the value thread-1 get the value thread-2 get the value thread-3 get the value thread-4 get the value thread-0 put value successful thread-1 put value successful thread-2 put value successful thread-3 put value successful thread-4 put value successful ...上述执行结果看似没有问题,但是违背了写锁最核心的本质,也就是如果有一个线程想取写共享资源来,就不应该允许其他线程可以对资源进行读或写
所以出现问题,此时就需要用到我们的读写锁,我们对我们自己的myLock()以及myUnlock()方法进行修改为使用读写锁的版本:
class MyCache { //定义缓存当中的数据结构为Map型,键为String,值为Object类型 private volatile Map<String, Object> map = new HashMap<>(); //读写锁 ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); /** * 写操作:原子+独占 * 整个过程必须是一个完整的统一体,中间不许被分割,不许被打断 * * @param key * @param value * */ //向Map中添加元素的方法 public void setMap(String key, Object value) { try { readWriteLock.writeLock().lock(); Thread thread = Thread.currentThread(); System.out.println(thread.getName() + "\t" + " put value:" + value); Thread.sleep(300); //底层的map直接put map.put(key, value); System.out.println(thread.getName() + "\t" + "put value successful"); } catch (Exception e) { e.printStackTrace(); } finally { readWriteLock.writeLock().unlock(); } } //向Map中取出元素 public void getMap(String key) { try { readWriteLock.readLock().lock(); Thread thread = Thread.currentThread(); System.out.println(thread.getName() + "\t" + "get the value"); Thread.sleep(300); //底层的map直接get,并且返回值为Object类型 Object retValue = map.get(key); System.out.println(thread.getName() + "\t" + "get the value successful, is " + retValue); } catch (Exception e) { e.printStackTrace(); } finally { readWriteLock.readLock().unlock(); } } }之后运行结果变成:
thread-1 put value:1 thread-1 put value successful thread-0 put value:0 thread-0 put value successful thread-2 put value:2 thread-2 put value successful thread-3 put value:3 thread-3 put value successful thread-4 put value:4 thread-4 put value successful thread-0 get the value thread-1 get the value thread-2 get the value thread-4 get the value thread-3 get the value thread-2 get the value successful, is 2 thread-3 get the value successful, is 3 thread-0 get the value successful, is 0 thread-4 get the value successful, is 4 thread-1 get the value successful, is 1也就对应上了写锁独占,必须当每一个写锁对应写操作完成之后,才可以进行下一次写操作,但是对于读操作,就可以多个线程共享,一起去缓存中读取数据