ソースを参照

除JDK原生读写锁之外,增加手工实现的简单读写锁;
排除了线程占用的检查,适用于跨线程锁操作的情况

luoshi 6 年 前
コミット
c09825aa25

+ 101 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/lock/impl/CustomLockProvider.java

@@ -0,0 +1,101 @@
+package cn.com.qmth.stmms.biz.lock.impl;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.springframework.stereotype.Component;
+
+import cn.com.qmth.stmms.biz.lock.LockProvider;
+import cn.com.qmth.stmms.common.enums.LockType;
+
+/**
+ * 自己实现的内存锁控制
+ * 
+ * @author luoshi
+ *
+ */
+@Component("customLockProvider")
+public class CustomLockProvider implements LockProvider {
+
+    private Map<LockType, Map<String, ReadWriteLock>> lockMap = new HashMap<>();
+
+    @Override
+    public void waitLock(LockType type, String key) {
+        getLock(type, key).write();
+    }
+
+    @Override
+    public boolean tryLock(LockType type, String key) {
+        return getLock(type, key).tryWrite();
+    }
+
+    @Override
+    public boolean isLocked(LockType type, String key) {
+        return getLock(type, key).writing();
+    }
+
+    @Override
+    public void unlock(LockType type, String key) {
+        getLock(type, key).unWrite();
+    }
+
+    @Override
+    public void watch(LockType type, String key) {
+        getLock(type, key).read();
+    }
+
+    @Override
+    public void unwatch(LockType type, String key) {
+        getLock(type, key).unRead();
+    }
+
+    private ReadWriteLock getLock(LockType type, String key) {
+        Map<String, ReadWriteLock> map = lockMap.get(type);
+        if (map == null) {
+            synchronized (lockMap) {
+                map = lockMap.get(type);
+                if (map == null) {
+                    map = new HashMap<>();
+                    lockMap.put(type, map);
+                }
+            }
+        }
+
+        ReadWriteLock lock = map.get(key);
+        if (lock == null) {
+            synchronized (map) {
+                lock = map.get(key);
+                if (lock == null) {
+                    lock = new ReadWriteLock();
+                    map.put(key, lock);
+                }
+            }
+        }
+
+        return lock;
+    }
+
+    public void clear() {
+        if (lockMap.isEmpty()) {
+            return;
+        }
+        synchronized (lockMap) {
+            for (Map<String, ReadWriteLock> map : lockMap.values()) {
+                Set<String> keys = new HashSet<>();
+                for (Entry<String, ReadWriteLock> entry : map.entrySet()) {
+                    if (!entry.getValue().writing() && entry.getValue().readCount() == 0) {
+                        keys.add(entry.getKey());
+                    }
+                }
+                for (String key : keys) {
+                    map.remove(key);
+                }
+                keys.clear();
+            }
+        }
+    }
+
+}

+ 128 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/lock/impl/ReadWriteLock.java

@@ -0,0 +1,128 @@
+package cn.com.qmth.stmms.biz.lock.impl;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.IntUnaryOperator;
+
+/**
+ * 简单读写锁实现<br>
+ * 0表示空闲状态,-1表示正在写,>0表示正在读
+ * 
+ * @author luoshi
+ *
+ */
+public class ReadWriteLock {
+
+    private static ReadOperator readOperator = new ReadOperator();
+
+    private static UnReadOperator unreadOperator = new UnReadOperator();
+
+    private AtomicInteger value;
+
+    public ReadWriteLock() {
+        this.value = new AtomicInteger(0);
+    }
+
+    public int read() {
+        int result = 0;
+        while ((result = value.updateAndGet(readOperator)) < 1) {
+            ;
+        }
+        return result;
+    }
+
+    public int unRead() {
+        return value.updateAndGet(unreadOperator);
+    }
+
+    public int readCount() {
+        return Math.max(0, value.get());
+    }
+
+    public int write() {
+        while (!value.compareAndSet(0, -1)) {
+            ;
+        }
+        return -1;
+    }
+
+    public boolean tryWrite() {
+        return value.compareAndSet(0, -1);
+    }
+
+    public int unWrite() {
+        while (!value.compareAndSet(-1, 0)) {
+            ;
+        }
+        return 0;
+    }
+
+    public boolean writing() {
+        return value.get() == -1;
+    }
+
+    static class ReadOperator implements IntUnaryOperator {
+
+        @Override
+        public int applyAsInt(int operand) {
+            return operand >= 0 ? operand + 1 : operand;
+        }
+
+    }
+
+    static class UnReadOperator implements IntUnaryOperator {
+
+        @Override
+        public int applyAsInt(int operand) {
+            return operand >= 1 ? operand - 1 : operand;
+        }
+
+    }
+
+    static class LockTestThread implements Runnable {
+
+        private ReadWriteLock lock;
+
+        private int number;
+
+        public LockTestThread(int number, ReadWriteLock lock) {
+            this.lock = lock;
+            this.number = number;
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < 10000; i++) {
+                if (Math.random() < 0.7) {
+                    System.out.println("thread " + number + " read:" + lock.read());
+                    try {
+                        Thread.sleep(100 * ((i % 10) + 1));
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                    System.out.println("thread " + number + " unread:" + lock.unRead());
+                } else {
+                    System.out.println("thread " + number + " write:" + lock.write());
+                    try {
+                        Thread.sleep(100 * ((i % 10) + 1));
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                    System.out.println("thread " + number + " unwrite:" + lock.unWrite());
+                }
+            }
+        }
+    }
+
+    public static void main(String[] args) {
+        ExecutorService executor = Executors.newFixedThreadPool(5);
+        final ReadWriteLock lock = new ReadWriteLock();
+        for (int i = 0; i < 5; i++) {
+            executor.submit(new LockTestThread(i + 1, lock));
+        }
+
+        executor.shutdown();
+    }
+
+}