一个资源可以被多个线程访问,或者可以被一个写线程访问,但是不能同时存在读写线程,读写互斥,读读共享的

无锁

多线程抢夺资源,乱

synchronized和ReentrantLock

读读和写写都只能一个来操作

ReentrantReadWriteLock

读读可以共享
写写只能一个操作

读写锁ReentrantReadWriteLock

  1. package com.daijunyi.lock;
  2. import java.util.HashMap;
  3. import java.util.Random;
  4. import java.util.concurrent.TimeUnit;
  5. import java.util.concurrent.locks.ReentrantReadWriteLock;
  6. class Cache{
  7. private volatile HashMap<String,Object> map = new HashMap<>();
  8. //读写锁
  9. private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
  10. public void put(String key,String value){
  11. rwLock.writeLock().lock();
  12. try {
  13. System.out.println(Thread.currentThread().getName()+"开始做存储操作");
  14. TimeUnit.SECONDS.sleep(new Random().nextInt(5));
  15. map.put(key,value);
  16. System.out.println(Thread.currentThread().getName()+"+++存储完成");
  17. } catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }finally {
  20. rwLock.writeLock().unlock();
  21. }
  22. }
  23. public Object get(String key){
  24. rwLock.readLock().lock();
  25. Object value = null;
  26. try {
  27. System.out.println(Thread.currentThread().getName()+"---读操作");
  28. TimeUnit.SECONDS.sleep(new Random().nextInt(4));
  29. value = map.get(key);
  30. System.out.println(Thread.currentThread().getName()+"读操作完成");
  31. } catch (InterruptedException e) {
  32. e.printStackTrace();
  33. } finally {
  34. rwLock.readLock().unlock();
  35. }
  36. return value;
  37. }
  38. }
  39. //读写锁
  40. public class ReadWriteDemo {
  41. public static void main(String[] args) {
  42. Cache cache = new Cache();
  43. //写操作
  44. for (int i=0;i<4;i++){
  45. final String num = String.valueOf(i);
  46. new Thread(()->{
  47. cache.put(num,num);
  48. },num).start();
  49. }
  50. //读操作
  51. for (int i=0;i<4;i++){
  52. final String num = String.valueOf(i);
  53. new Thread(()->{
  54. Object o = cache.get(num);
  55. System.out.println("读操作"+o);
  56. },num).start();
  57. }
  58. }
  59. }

运行结果

/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/bin/java -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/tools.jar:/Users/djy/WorkFile/learn/juc/picker/target/classes com.daijunyi.lock.ReadWriteDemo
0开始做存储操作
0+++存储完成
1开始做存储操作
1+++存储完成
2开始做存储操作
2+++存储完成
3开始做存储操作
3+++存储完成
0---读操作
1---读操作
2---读操作
3---读操作
2读操作完成
读操作2
3读操作完成
读操作3
0读操作完成
读操作0
1读操作完成
读操作1

Process finished with exit code 0

锁降级:将写入锁降级为读锁

锁降级的必要性:
锁降级中读锁的获取是否必要呢?答案是必要的。主要是为了保证数据的可见性,如果当前线程不获取读锁而是直接释放写锁, 假设此刻另一个线程(记作线程T)获取了写锁并修改了数据,那么当前线程无法感知线程T的数据更新。如果当前线程获取读锁,即遵循锁降级的步骤,则线程T将会被阻塞,直到当前线程使用数据并释放读锁之后,线程T才能获取写锁进行数据更新。
这时因为可能存在一个事务线程不希望自己的操作被别的线程中断,而这个事务操作可能分成多部分操作更新不同的数据(或表)甚至非常耗时。如果长时间用写锁独占,显然对于某些高响应的应用是不允许的,所以在完成部分写操作后,退而使用读锁降级,来允许响应其他进程的读操作。只有当全部事务完成后才真正释放锁。
所以总结下锁降级的意义应该就是:在一边读一边写的情况下提高性能。
image.png

package com.daijunyi.lock;

import java.util.concurrent.locks.ReentrantReadWriteLock;

//演示读写锁降级
public class ReadWriteDemo2 {

    public static void main(String[] args) {
        //可重入读写锁对象创建
        ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
        ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
        ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();

        //锁降级
        //1 获取到写锁
        writeLock.lock();
        System.out.println("获取到写锁,做写入操作");

        //获取读锁
        readLock.lock();
        System.out.println("获取读锁");

        //释放写锁
        writeLock.unlock();
        System.out.println("释放写锁");

        //释放读锁
        readLock.unlock();
        System.out.println("释放读锁");
    }

}

运行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/bin/java -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/lib/tools.jar:/Users/djy/WorkFile/learn/juc/picker/target/classes com.daijunyi.lock.ReadWriteDemo2
获取到写锁
获取读锁
释放写锁
释放读锁

Process finished with exit code 0