|
@@ -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;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|