8.读写锁
8.1 ReadWriteLock接口
java.util.concurrent.locks 下的Interface ReadWriteLock下的唯一的一个实现类为ReentrantReadWriteLock,可重入读写锁可以被多个线程同时读,但是只能有一个线程去写。
-
独占锁(写锁) 一次只能被一个线程占有
-
共享锁(读锁) 多个线程可以同时占有,这样还能提高程序效率
-
线程之间的读-读 可以共存!
-
线程之间的读-写 不能共存!
-
线程之间的写-写 不能共存!
下面的代码MyCache资源类没有枷锁,所以在写的时候,会出现一个线程在写,就类似一个线程要写6个字,写了一个字的时候,另一个线程进来写了3个字,然后那个原来的线程继续写,这就不对了,会造成混乱。
而加锁后MyCacheLock资源类,则就能使得每个线程都在写完的状态下才能进行下一个线程的写入保证了安全性,同时使得多个线程可以读入,提高了效率。
package com.rw; 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.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteLockDemo { public static void main(String[] args) { MyCache myCache = new MyCache(); // 写入 for (int i = 1; i <= 6 ; i++) { final int temp = i; new Thread(()->{ myCache.put(temp+"",temp+""); },String.valueOf(i)).start(); } // 读取 for (int i = 1; i <= 6 ; i++) { final int temp = i; new Thread(()->{ myCache.get(temp+""); },String.valueOf(i)).start(); } } } // 加锁的 class MyCacheLock{ private volatile Map<String,Object> map = new HashMap<>(); // 读写锁: 更加细粒度的控制 private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); //如果只是ReentrantLock()做不到读的时候多个线程去读 private Lock lock = new ReentrantLock(); // 存,写入的时候,只希望同时只有一个线程写 public void put(String key,Object value){ readWriteLock.writeLock().lock(); try { System.out.println(Thread.currentThread().getName()+"写入"+key); map.put(key,value); System.out.println(Thread.currentThread().getName()+"写入OK"); } catch (Exception e) { e.printStackTrace(); } finally { readWriteLock.writeLock().unlock(); } } // 取,读,所有人都可以读 public void get(String key){ readWriteLock.readLock().lock(); try { System.out.println(Thread.currentThread().getName()+"读取"+key); Object o = map.get(key); System.out.println(Thread.currentThread().getName()+"读取OK"); } catch (Exception e) { e.printStackTrace(); } finally { readWriteLock.readLock().unlock(); } } } /** * 自定义缓存,在这就是线程操作的资源类,封装为一起 */ class MyCache{ private volatile Map<String,Object> map = new HashMap<>(); // 存,写 public void put(String key,Object value){ System.out.println(Thread.currentThread().getName()+"写入"+key); map.put(key,value); System.out.println(Thread.currentThread().getName()+"写入OK"); } // 取,读 public void get(String key){ System.out.println(Thread.currentThread().getName()+"读取"+key); Object o = map.get(key); System.out.println(Thread.currentThread().getName()+"读取OK"); } }
package com.rw; 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.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteLockDemo { public static void main(String[] args) { MyCache myCache = new MyCache(); // 写入 for (int i = 1; i <= 6 ; i++) { final int temp = i; new Thread(()->{ myCache.put(temp+"",temp+""); },String.valueOf(i)).start(); } // 读取 for (int i = 1; i <= 6 ; i++) { final int temp = i; new Thread(()->{ myCache.get(temp+""); },String.valueOf(i)).start(); } } } // 加锁的 class MyCacheLock{ private volatile Map<String,Object> map = new HashMap<>(); // 读写锁: 更加细粒度的控制 private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); //如果只是ReentrantLock()做不到读的时候多个线程去读 private Lock lock = new ReentrantLock(); // 存,写入的时候,只希望同时只有一个线程写 public void put(String key,Object value){ readWriteLock.writeLock().lock(); try { System.out.println(Thread.currentThread().getName()+"写入"+key); map.put(key,value); System.out.println(Thread.currentThread().getName()+"写入OK"); } catch (Exception e) { e.printStackTrace(); } finally { readWriteLock.writeLock().unlock(); } } // 取,读,所有人都可以读 public void get(String key){ readWriteLock.readLock().lock(); try { System.out.println(Thread.currentThread().getName()+"读取"+key); Object o = map.get(key); System.out.println(Thread.currentThread().getName()+"读取OK"); } catch (Exception e) { e.printStackTrace(); } finally { readWriteLock.readLock().unlock(); } } } /** * 自定义缓存,在这就是线程操作的资源类,封装为一起 */ class MyCache{ private volatile Map<String,Object> map = new HashMap<>(); // 存,写 public void put(String key,Object value){ System.out.println(Thread.currentThread().getName()+"写入"+key); map.put(key,value); System.out.println(Thread.currentThread().getName()+"写入OK"); } // 取,读 public void get(String key){ System.out.println(Thread.currentThread().getName()+"读取"+key); Object o = map.get(key); System.out.println(Thread.currentThread().getName()+"读取OK"); } }
(1)没加锁,被插队了
(2)加锁,保证一个线程执行完再执行其他的
上面那三个接口都是locks包下的接口。