Parcourir la source

新的评卷任务控制内存锁实现,尚未正式使用

luoshi il y a 6 ans
Parent
commit
2971cf6320

+ 290 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/utils/TaskCache.java

@@ -0,0 +1,290 @@
+package cn.com.qmth.stmms.biz.mark.utils;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.ReentrantLock;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.SetMultimap;
+
+/**
+ * 一个评卷任务集合的状态控制工具
+ * 
+ * @author luoshi
+ *
+ */
+public class TaskCache {
+
+    private volatile ReentrantLock lock;
+
+    private Map<Integer, TaskStatus> libraryMap;
+
+    private SetMultimap<Integer, Integer> studentMap;
+
+    public Map<Integer, TaskStatus> finishLibrary;
+
+    private SetMultimap<Integer, Integer> finishStudent;
+
+    private AtomicInteger applyCount, finishCount;
+
+    private AtomicLong applyTime, finishTime;
+
+    public TaskCache() {
+        this.lock = new ReentrantLock();
+        this.libraryMap = new ConcurrentHashMap<>();
+        this.finishLibrary = new ConcurrentHashMap<>();
+        this.studentMap = HashMultimap.create();
+        this.finishStudent = HashMultimap.create();
+
+        this.applyCount = new AtomicInteger(0);
+        this.finishCount = new AtomicInteger(0);
+        this.applyTime = new AtomicLong(0);
+        this.finishTime = new AtomicLong(0);
+    }
+
+    public boolean apply(Integer libraryId, Integer studentId, Integer markerId) {
+        long start = System.currentTimeMillis();
+        try {
+            lock.lock();
+
+            if (finishLibrary.containsKey(libraryId)) {
+                return false;
+            }
+            if (finishStudent.containsEntry(studentId, markerId)) {
+                return false;
+            }
+            if (studentMap.containsEntry(studentId, markerId)) {
+                return false;
+            }
+            if (libraryMap.get(libraryId) != null) {
+                return false;
+            }
+
+            libraryMap.put(libraryId, new TaskStatus(libraryId, studentId, markerId));
+            studentMap.put(studentId, markerId);
+            return true;
+        } catch (Exception e) {
+            return false;
+        } finally {
+            lock.unlock();
+
+            applyCount.incrementAndGet();
+            applyTime.addAndGet(System.currentTimeMillis() - start);
+        }
+    }
+
+    public boolean hasApplied(Integer libraryId, Integer markerId) {
+        TaskStatus status = libraryMap.get(libraryId);
+        return status != null && status.getMarkerId().equals(markerId);
+    }
+
+    public void finish(Integer libraryId, Integer studentId, Integer markerId) {
+        long start = System.currentTimeMillis();
+        try {
+            lock.lock();
+
+            libraryMap.remove(libraryId);
+            studentMap.remove(studentId, markerId);
+            finishLibrary.put(libraryId, new TaskStatus(libraryId, studentId, markerId));
+            finishStudent.put(studentId, markerId);
+        } catch (Exception e) {
+        } finally {
+            lock.unlock();
+
+            finishCount.incrementAndGet();
+            finishTime.addAndGet(System.currentTimeMillis() - start);
+        }
+    }
+
+    public int applyCount() {
+        return libraryMap.size();
+    }
+
+    public int applyCount(Integer markerId) {
+        int count = 0;
+        for (TaskStatus status : libraryMap.values()) {
+            if (status.getMarkerId().equals(markerId)) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    public void clearApply() {
+        try {
+            lock.lock();
+
+            libraryMap.clear();
+            studentMap.clear();
+        } catch (Exception e) {
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public void clearApply(Integer markerId) {
+        try {
+            lock.lock();
+
+            Set<Integer> set = new HashSet<>();
+            for (TaskStatus status : libraryMap.values()) {
+                if (status.getMarkerId().equals(markerId)) {
+                    studentMap.remove(status.getStudentId(), status.getMarkerId());
+                    set.add(status.getLibraryId());
+                }
+            }
+            for (Integer libraryId : set) {
+                libraryMap.remove(libraryId);
+            }
+        } catch (Exception e) {
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public void reset() {
+        try {
+            lock.lock();
+
+            libraryMap.clear();
+            studentMap.clear();
+            finishLibrary.clear();
+            finishStudent.clear();
+        } catch (Exception e) {
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public void reset(Integer markerId) {
+        try {
+            lock.lock();
+
+            Set<Integer> set = new HashSet<>();
+            for (TaskStatus status : libraryMap.values()) {
+                if (status.getMarkerId().equals(markerId)) {
+                    studentMap.remove(status.getStudentId(), status.getMarkerId());
+                    set.add(status.getLibraryId());
+                }
+            }
+            for (Integer libraryId : set) {
+                libraryMap.remove(libraryId);
+            }
+
+            set.clear();
+            for (TaskStatus status : finishLibrary.values()) {
+                if (status.getMarkerId().equals(markerId)) {
+                    finishStudent.remove(status.getStudentId(), status.getMarkerId());
+                    set.add(status.getLibraryId());
+                }
+            }
+            for (Integer libraryId : set) {
+                finishLibrary.remove(libraryId);
+            }
+        } catch (Exception e) {
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public static void main(String[] args) throws InterruptedException {
+        ExecutorService executor = Executors.newFixedThreadPool(50);
+        TaskCache cache = new TaskCache();
+        List<Integer> libraryList = new ArrayList<>(100000);
+        for (int i = 1; i <= 100000; i++) {
+            libraryList.add(i);
+        }
+
+        List<MarkerThread> threads = new ArrayList<>(100);
+        for (int i = 1; i <= 100; i++) {
+            MarkerThread thread = new MarkerThread(cache, libraryList, i);
+            threads.add(thread);
+            executor.submit(thread);
+        }
+
+        executor.shutdown();
+        while (!executor.isTerminated()) {
+            Thread.sleep(10000);
+            System.out.println("finish count: " + cache.finishLibrary.size());
+        }
+        int count = 0;
+        for (MarkerThread thread : threads) {
+            count += thread.librarySet.size();
+        }
+        if (count != libraryList.size()) {
+            System.out.println("library count error: " + count);
+        }
+
+        System.out.println("apply avg time: " + (cache.applyTime.get() * 1.0 / cache.applyCount.get()));
+        System.out.println("finish avg time: " + (cache.finishTime.get() * 1.0 / cache.finishCount.get()));
+    }
+
+    static class MarkerThread implements Runnable {
+
+        private TaskCache cache;
+
+        private Integer id;
+
+        private List<Integer> libraryList;
+
+        private Set<Integer> librarySet;
+
+        private Set<Integer> studentSet;
+
+        public MarkerThread(TaskCache cache, List<Integer> libraryList, Integer id) {
+            this.cache = cache;
+            this.libraryList = libraryList;
+            this.id = id;
+            this.librarySet = new HashSet<>();
+            this.studentSet = new HashSet<>();
+        }
+
+        @Override
+        public void run() {
+            Integer libraryId = null;
+            while ((libraryId = getLibrary()) != null) {
+                if (librarySet.contains(libraryId)) {
+                    System.out.println("library redo: " + libraryId + "," + id);
+                }
+                Integer studentId = (libraryId + 1) / 2;
+                if (studentSet.contains(studentId)) {
+                    System.out.println("student redo: " + libraryId + "," + studentId + "," + id);
+                }
+
+                // long time = Math.max((long) (Math.random() * 5000), 500);
+                // try {
+                // Thread.sleep(time);
+                // } catch (InterruptedException e) {
+                // e.printStackTrace();
+                // }
+
+                if (!cache.hasApplied(libraryId, id)) {
+                    System.out.println("applyed error: " + studentId + "," + id);
+                }
+                cache.finish(libraryId, studentId, id);
+
+                librarySet.add(libraryId);
+                studentSet.add(studentId);
+            }
+        }
+
+        private Integer getLibrary() {
+            for (Integer libraryId : libraryList) {
+                if (cache.apply(libraryId, (libraryId + 1) / 2, id)) {
+                    return libraryId;
+                }
+            }
+            return null;
+        }
+
+    }
+
+}

+ 52 - 0
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/mark/utils/TaskStatus.java

@@ -0,0 +1,52 @@
+package cn.com.qmth.stmms.biz.mark.utils;
+
+public class TaskStatus {
+
+    private Integer libraryId;
+
+    private Integer studentId;
+
+    private Integer markerId;
+
+    private long time;
+
+    public TaskStatus(Integer libraryId, Integer studentId, Integer markerId) {
+        this.libraryId = libraryId;
+        this.studentId = studentId;
+        this.markerId = markerId;
+        this.time = System.currentTimeMillis();
+    }
+
+    public Integer getLibraryId() {
+        return libraryId;
+    }
+
+    public void setLibraryId(Integer libraryId) {
+        this.libraryId = libraryId;
+    }
+
+    public Integer getStudentId() {
+        return studentId;
+    }
+
+    public void setStudentId(Integer studentId) {
+        this.studentId = studentId;
+    }
+
+    public Integer getMarkerId() {
+        return markerId;
+    }
+
+    public void setMarkerId(Integer markerId) {
+        this.markerId = markerId;
+    }
+
+    public long getTime() {
+        return time;
+    }
+
+    public void setTime(long time) {
+        this.time = time;
+    }
+
+}