浏览代码

重新修改锁机制,并增加自动清理功能,防止内存占用过多

luoshi 6 年之前
父节点
当前提交
e38a9bea85

+ 16 - 1
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkCronService.java

@@ -58,13 +58,28 @@ public class MarkCronService {
     @Autowired
     private MarkService markService;
 
+    @Autowired
+    private MarkLockService lockService;
+
     @Value("${mark.cleanTimeoutMinute}")
     private long timeoutMinute;
 
+    /**
+     * 自动释放可清除的锁
+     */
+    @Scheduled(cron = "${mark.cleanLockSchedule}")
+    public void cronCleanLock() {
+        try {
+            lockService.clear();
+        } catch (Exception e) {
+            log.error("CronCleanTask error", e);
+        }
+    }
+
     /**
      * 自动释放超时未处理的评卷任务
      */
-    @Scheduled(cron = "${mark.cleanSchedule}")
+    @Scheduled(cron = "${mark.cleanTaskSchedule}")
     public void cronCleanTask() {
         try {
             CurrentTaskUtil.clearTimeoutTask(timeoutMinute);

+ 64 - 10
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/service/Impl/MarkLockService.java

@@ -1,7 +1,11 @@
 package cn.com.qmth.stmms.biz.mark.service.Impl;
 
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -19,9 +23,9 @@ public class MarkLockService {
 
     protected static final Logger log = LoggerFactory.getLogger(MarkLockService.class);
 
-    private Map<String, Boolean> groupMap = new ConcurrentHashMap<>();
+    private Map<Object, AtomicBoolean> groupMap = new HashMap<>();
 
-    private Map<Integer, Boolean> studentMap = new ConcurrentHashMap<>();
+    private Map<Object, AtomicBoolean> studentMap = new HashMap<>();
 
     /**
      * 对评卷分组进行重置/删除操作前,先尝试锁定
@@ -29,7 +33,10 @@ public class MarkLockService {
      * @param group
      */
     public void lockGroup(Integer examId, String subjectCode, Integer groupNumber) {
-        groupMap.put(getKey(examId, subjectCode, groupNumber), Boolean.TRUE);
+        AtomicBoolean lock = getLock(groupMap, getKey(examId, subjectCode, groupNumber));
+        while (!lock.get()) {
+            lock.compareAndSet(false, true);
+        }
     }
 
     /**
@@ -38,7 +45,10 @@ public class MarkLockService {
      * @param group
      */
     public void unlockGroup(Integer examId, String subjectCode, Integer groupNumber) {
-        groupMap.remove(getKey(examId, subjectCode, groupNumber));
+        AtomicBoolean lock = getLock(groupMap, getKey(examId, subjectCode, groupNumber));
+        while (lock != null && lock.get()) {
+            lock.compareAndSet(true, false);
+        }
     }
 
     /**
@@ -47,8 +57,8 @@ public class MarkLockService {
      * @param group
      */
     public void waitUnlockGroup(Integer examId, String subjectCode, Integer groupNumber) {
-        String key = getKey(examId, subjectCode, groupNumber);
-        while (groupMap.get(key) != null) {
+        AtomicBoolean lock = getLock(groupMap, getKey(examId, subjectCode, groupNumber));
+        while (lock.get()) {
             ;
         }
     }
@@ -59,7 +69,10 @@ public class MarkLockService {
      * @param studentId
      */
     public void lockStudent(Integer studentId) {
-        studentMap.put(studentId, Boolean.TRUE);
+        AtomicBoolean lock = getLock(studentMap, studentId);
+        while (!lock.get()) {
+            lock.compareAndSet(false, true);
+        }
     }
 
     /**
@@ -68,7 +81,10 @@ public class MarkLockService {
      * @param studentId
      */
     public void unlockStudent(Integer studentId) {
-        studentMap.remove(studentId);
+        AtomicBoolean lock = getLock(studentMap, studentId);
+        while (lock.get()) {
+            lock.compareAndSet(true, false);
+        }
     }
 
     /**
@@ -77,11 +93,49 @@ public class MarkLockService {
      * @param studentId
      */
     public void waitUnlockStudent(Integer studentId) {
-        while (studentMap.get(studentId) != null) {
+        AtomicBoolean lock = getLock(studentMap, studentId);
+        while (lock.get()) {
             ;
         }
     }
 
+    public void clear() {
+        clearLock(groupMap);
+        clearLock(studentMap);
+    }
+
+    private void clearLock(Map<Object, AtomicBoolean> map) {
+        if (map.isEmpty()) {
+            return;
+        }
+        synchronized (map) {
+            Set<Object> keys = new HashSet<>();
+            for (Entry<Object, AtomicBoolean> entry : map.entrySet()) {
+                if (!entry.getValue().get()) {
+                    keys.add(entry.getKey());
+                }
+            }
+            for (Object key : keys) {
+                map.remove(key);
+            }
+            keys.clear();
+        }
+    }
+
+    private AtomicBoolean getLock(Map<Object, AtomicBoolean> map, Object key) {
+        AtomicBoolean lock = map.get(key);
+        if (lock == null) {
+            synchronized (map) {
+                lock = map.get(key);
+                if (lock == null) {
+                    lock = new AtomicBoolean(false);
+                    map.put(key, lock);
+                }
+            }
+        }
+        return lock;
+    }
+
     private String getKey(Integer examId, String subjectCode, Integer groupNumber) {
         return examId + "_" + subjectCode + "_" + groupNumber;
     }

+ 2 - 1
stmms-web/src/main/webapp/WEB-INF/application.properties

@@ -37,6 +37,7 @@ upyun.slice.username=qmth-picture
 upyun.slice.password=qmth12345678
 
 mark.cleanTimeoutMinute=20
-mark.cleanSchedule=0 0/10 6-23 * * ?
+mark.cleanTaskSchedule=0 0/10 6-23 * * ?
+mark.cleanLockSchedule=0 0 3 * * ?
 
 marker.showBtnImportAndBtnUpdateImport=false