先改造
package com.study.framework.annotation; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @Description: 自定义,线程安全的 map ,用读写锁改造HashMap * @Auther: BacHe * @Date: 2019/9/19 09:46 */ public class SafeMap { //非线程安全的map private static Map<String, Object> map = new HashMap<>(); //可重入读写锁 private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); //读锁 private static Lock r = lock.readLock(); //写锁 private static Lock w = lock.writeLock(); //获取一个key 对应的值 public static final Object get(String key) { //加 读锁 r.lock(); Object obj = null; try { obj = map.get(key); } catch (Exception e) { e.printStackTrace(); } finally { //释放锁 r.unlock(); } return obj; } //设置 key 对应的value public static final Object put(String key, Object value) { //加 写锁 w.lock(); Object obj = null; try { obj = map.put(key, value); } catch (Exception e) { e.printStackTrace(); } finally { //释放锁 w.unlock(); } return obj; } //清空所有的内容 public static final void clear() { //加 写锁 w.lock(); try { map.clear(); } catch (Exception e) { e.printStackTrace(); } finally { //释放锁 w.unlock(); } } }
测试一下是不是线程安全
package com.study.framework; import com.study.framework.annotation.SafeMap; import java.util.concurrent.atomic.AtomicInteger; /** * @Description: * @Auther: BacHe * @Date: 2019/9/19 10:09 */ public class SafeMapTest { public static void main(String[] args) { //定义原子变量 AtomicInteger integer = new AtomicInteger(0); //定义写入线程 for (int i = 0; i < 1; i++) { new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(1200); } catch (InterruptedException e) { e.printStackTrace(); } int andAdd = integer.getAndAdd(1); Object a = SafeMap.put("a", String.valueOf(andAdd)); if (null == a) { a = "null"; } System.out.println(Thread.currentThread().getName() + ",---上一个值:" + a.toString() +",---put入:" + String.valueOf(andAdd)); } } },"写线程:"+String.valueOf(i+1)).start(); } //定义读取线程 for (int i = 0; i < 3; i++) { new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } Object a = SafeMap.get("a"); if (null != a) { System.out.println(Thread.currentThread().getName() + ",----" + a.toString()); } else { System.out.println(Thread.currentThread().getName() + ",----null"); } } } }, "读线程:" + String.valueOf(i + 1)).start(); } } }
观察输出结果,确实是读的时候不会写,写的时候不会读。避免出现脏读现象。
读线程:1,----null 读线程:2,----null 读线程:3,----null 读线程:3,----null 读线程:2,----null 读线程:1,----null 写线程:1,---上一个值:null,---put入:0 读线程:1,----0 读线程:2,----0 读线程:3,----0 读线程:2,----0 读线程:1,----0 读线程:3,----0 写线程:1,---上一个值:0,---put入:1 读线程:3,----1 读线程:2,----1 读线程:1,----1 读线程:3,----1 读线程:1,----1 读线程:2,----1 读线程:1,----1 读线程:2,----1 读线程:3,----1 写线程:1,---上一个值:1,---put入:2 读线程:1,----2 读线程:3,----2 读线程:2,----2 读线程:1,----2 读线程:2,----2 读线程:3,----2 写线程:1,---上一个值:2,---put入:3 读线程:2,----3 读线程:1,----3 读线程:3,----3 读线程:3,----3 读线程:1,----3 读线程:2,----3 写线程:1,---上一个值:3,---put入:4 读线程:1,----4 读线程:3,----4 读线程:2,----4 读线程:3,----4 读线程:2,----4 读线程:1,----4 读线程:1,----4 读线程:3,----4 读线程:2,----4 写线程:1,---上一个值:4,---put入:5 读线程:2,----5 读线程:3,----5 读线程:1,----5 读线程:1,----5 读线程:2,----5 读线程:3,----5 写线程:1,---上一个值:5,---put入:6 读线程:1,----6 读线程:3,----6 读线程:2,----6 读线程:1,----6 读线程:2,----6 读线程:3,----6 读线程:1,----6 读线程:3,----6 读线程:2,----6 写线程:1,---上一个值:6,---put入:7 读线程:3,----7 读线程:2,----7 读线程:1,----7 读线程:1,----7 读线程:3,----7 读线程:2,----7 写线程:1,---上一个值:7,---put入:8 读线程:2,----8 读线程:1,----8 读线程:3,----8 读线程:2,----8 读线程:1,----8 读线程:3,----8 写线程:1,---上一个值:8,---put入:9 读线程:2,----9 读线程:1,----9 读线程:3,----9 读线程:3,----9 读线程:1,----9 读线程:2,----9 读线程:2,----9 读线程:3,----9 读线程:1,----9 写线程:1,---上一个值:9,---put入:10 读线程:3,----10 读线程:2,----10 读线程:1,----10 读线程:3,----10 读线程:1,----10 读线程:2,----10 写线程:1,---上一个值:10,---put入:11 读线程:3,----11 读线程:1,----11 读线程:2,----11 读线程:3,----11 读线程:2,----11 读线程:1,----11
嗯,就是这样。