1 package cn.xxx.xxx; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 import java.util.concurrent.locks.ReadWriteLock; 6 import java.util.concurrent.locks.ReentrantReadWriteLock; 7 8 public class CacheDemo_My { 9 10 public static void main(String[] args) { 11 // 内部类 实例化时需要在 内部类前加static 关键字 12 final CacheClass cacheClass = new CacheClass(); 13 for (int i = 0; i < 10; i++) { 14 new Thread(new Runnable() { 15 16 @Override 17 public void run() { 18 Object valueObject = cacheClass.getData("1"); 19 System.out.println(Thread.currentThread().getName() + " : " + valueObject); 20 } 21 }).start(); 22 } 23 } 24 25 26 static class CacheClass { 27 private Map<String, Object> cacheMap = new HashMap<String, Object>(); 28 29 /** 30 * 1.0 没有考虑并发 问题: 从数据库查了两次 31 * 从数据库查询数据! 32 * 从数据库查询数据! 33 * Thread-1 : null 为什么是null,并发了,过程如 Thread-0 所示 34 * Thread-2 : aaa 35 * Thread-0 :null 为什么是null,因为第一次读取map中没有值返回null,而cacheMap.put(key, "aaa")后 36 * 并没有重新赋值给object 所以是null 37 * 解决方案是 直接从cacheMap.get(key) 中获取,不要中间环节 object,这里我就不改了 38 * Thread-3 : aaa 39 * Thread-4 : aaa 40 * Thread-5 : aaa 41 * Thread-6 : aaa 42 * Thread-7 : aaa 43 * Thread-8: aaa 44 * Thread-9 : aaa 45 * 46 * @param key 47 * @return 48 */ 49 // public Object getData(String key) { 50 // Object value = cacheMap.get(key); 51 // if (value == null) { 52 // System.out.println("从数据库查询数据!"); 53 // cacheMap.put(key, "aaa"); 54 // } 55 // return value; 56 // } 57 58 /** 59 * 2.0 使用synchronized 同步 代码块 解决并发问题 实现方式简单 直接加synchronized 关键字 60 * 61 * 从数据库查询数据! 62 * Thread-4 : bbb 63 * Thread-1 : bbb 64 * Thread-2 : bbb 65 * Thread-0 : bbb 66 * Thread-3 : bbb 67 * Thread-8 : bbb 68 * Thread-7 : bbb 69 * Thread-6 : bbb 70 * Thread-9 : bbb 71 * Thread-5 : bbb 72 * 73 * @param key 74 * @return 75 */ 76 // public synchronized Object getData(String key){ 77 // 78 // if ( cacheMap.get(key)==null) { 79 // System.out.println("从数据库查询数据!"); 80 // cacheMap.put(key, "bbb"); 81 // } 82 // return cacheMap.get(key); 83 // } 84 85 /** 86 * 3.0 使用读写锁 87 * 88 从数据库查询数据! 89 Thread-1 : ccc 90 Thread-3 : ccc 91 Thread-4 : ccc 92 Thread-2 : ccc 93 Thread-0 : ccc 94 Thread-5 : ccc 95 Thread-7 : ccc 96 Thread-8 : ccc 97 Thread-9 : ccc 98 Thread-6 : ccc 99 */ 100 private ReadWriteLock rwl = new ReentrantReadWriteLock(); 101 public Object getData(String key) { 102 //加锁了就要try finally ,避免异常情况下 代码一直被锁 103 rwl.readLock().lock(); 104 try { 105 if (cacheMap.get(key) == null) { 106 try{ 107 //读锁 解掉 是为了写锁 加锁 108 rwl.readLock().unlock(); 109 //加锁了就要try finally ,避免异常情况下 代码一直被锁 110 rwl.writeLock().lock(); 111 // 避免第一个线程写完数据,后面的线程接着写 112 if (cacheMap.get(key) == null) { 113 System.out.println("从数据库查询数据!"); 114 cacheMap.put(key, "ccc"); 115 } 116 } 117 finally{ 118 rwl.writeLock().unlock(); 119 } 120 rwl.readLock().lock(); 121 } 122 } finally { 123 rwl.readLock().unlock(); 124 } 125 126 return cacheMap.get(key); 127 } 128 } 129 }