Java 如果是线程安全的,是否有机会实现更多并发

Java 如果是线程安全的,是否有机会实现更多并发,java,multithreading,java-threads,Java,Multithreading,Java Threads,AnagramGameDefault类模拟一个字谜游戏 SubmitCore()应该重新计算位置,得分最高的位置为1,同一位置上可以有多个玩家 getLeaderBoard()获取一个用户的条目加上上面两个和下面两个 我关注的是: 我测试了多个线程的代码,我想它正在工作,但我想知道代码中是否存在一些争用条件或共享状态失败 我通过使用“synchronized”使用了非常严格的互斥锁定。我不认为这是可以避免的,因为SubmitCore()和GetLeadboard()严重依赖于排序和正确的分数位置

AnagramGameDefault类模拟一个字谜游戏

SubmitCore()应该重新计算位置,得分最高的位置为1,同一位置上可以有多个玩家

getLeaderBoard()获取一个用户的条目加上上面两个和下面两个

我关注的是:

  • 我测试了多个线程的代码,我想它正在工作,但我想知道代码中是否存在一些争用条件或共享状态失败
  • 我通过使用“synchronized”使用了非常严格的互斥锁定。我不认为这是可以避免的,因为SubmitCore()和GetLeadboard()严重依赖于排序和正确的分数位置,但有可能吗?我读了一些关于ReentrantLock的内容,但它更适合于多读少写的情况,在这种情况下,即使是读也需要计算

    public enum AnagramGameDefault{
    
    INSTANCE;
    
    private Map<String, Entry> leaderBoardUserEntryMap;
    
    {
        leaderBoardUserEntryMap = new LinkedHashMap<>();
    }
    
    public int calculateScore(String word, String anagram) {
    
        if (word == null || anagram == null) {
            throw new NullPointerException("Both, word and anagram, must be non-null");
        }
    
        char[] wordArray = word.trim().toLowerCase().toCharArray();
        char[] anagramArray = anagram.trim().toLowerCase().toCharArray();
    
        int[] alphabetCountArray = new int[26];
    
        int reference = 'a';
    
        for (int i = 0; i < wordArray.length; i++) {
            if (!Character.isWhitespace(wordArray[i])) {
                alphabetCountArray[wordArray[i] - reference]++;
            }
        }
        for (int i = 0; i < anagramArray.length; i++) {
            if (!Character.isWhitespace(anagramArray[i])) {
                alphabetCountArray[anagramArray[i] - reference]--;
            }
        }
    
        for (int i = 0; i < 26; i++)
            if (alphabetCountArray[i] != 0)
                return 0;
    
        return word.length();
    
    }
    
    public void submitScore(String uid, int score) {
    
        Entry newEntry = new Entry(uid, score);
        sortLeaderBoard(newEntry);
    }
    
    private void sortLeaderBoard(Entry newEntry) {
    
        synchronized (leaderBoardUserEntryMap) {
            leaderBoardUserEntryMap.put(newEntry.getUid(), newEntry);
    
            // System.out.println("Sorting for " + newEntry);
    
            List<Map.Entry<String, Entry>> list = leaderBoardUserEntryMap.entrySet().stream()
                    .sorted(Map.Entry.comparingByValue(Collections.reverseOrder())).collect(Collectors.toList());
            leaderBoardUserEntryMap.clear();
    
            int position = 0;
            int previousPosition = 0;
            int currentPosition = 0;
    
            for (Map.Entry<String, Entry> entry : list) {
                currentPosition = entry.getValue().getScore();
                if (!(currentPosition == previousPosition))
                    position++;
    
                entry.getValue().setPosition(position);
                leaderBoardUserEntryMap.put(entry.getKey(), entry.getValue());
    
                previousPosition = currentPosition;
    
            }
        }
    
    }
    
    public List<Entry> getLeaderBoard(String uid) {
    
        final int maxEntriesAroundAnEntry = 2;
    
        if (!leaderBoardUserEntryMap.containsKey(uid))
            return Collections.emptyList();
    
        Entry userEntry = null;
    
        final List<Entry> leaderBoard = new ArrayList<>();
        List<Entry> lowerEntries = null;
        List<Entry> higherEntries = null;
    
        synchronized (leaderBoardUserEntryMap) {
    
            printBoard();
    
            userEntry = leaderBoardUserEntryMap.get(uid);
            int userPosition = userEntry.getPosition();
            int upperPosition = userPosition - maxEntriesAroundAnEntry;
            int lowerPosition = userPosition + maxEntriesAroundAnEntry;
    
            // Higher entries
            higherEntries = leaderBoardUserEntryMap.values().stream()
                    .filter(entry -> (entry.getPosition() < userPosition && entry.getPosition() >= upperPosition))
                    .map(entry -> new Entry(entry.getUid(), entry.getScore(), entry.getPosition()))
                    .collect(Collectors.toList());
    
            // Lower entries
            lowerEntries = leaderBoardUserEntryMap.values().stream()
                    .filter(entry -> (entry.getPosition() > userPosition && entry.getPosition() <= lowerPosition))
                    .map(entry -> new Entry(entry.getUid(), entry.getScore(), entry.getPosition()))
                    .collect(Collectors.toList());
    
            userEntry = new Entry(userEntry.getUid(), userEntry.getScore(), userEntry.getPosition());
    
            // }
    
            if (higherEntries != null && !higherEntries.isEmpty()) {
    
                if (higherEntries.size() >= maxEntriesAroundAnEntry) {
                    higherEntries = higherEntries.subList(higherEntries.size() - maxEntriesAroundAnEntry,
                            higherEntries.size());
                }
    
                leaderBoard.addAll(higherEntries);
            }
    
            leaderBoard.add(userEntry);
    
            if (lowerEntries != null && !lowerEntries.isEmpty()) {
    
                if (lowerEntries.size() >= maxEntriesAroundAnEntry) {
                    lowerEntries = lowerEntries.subList(0, maxEntriesAroundAnEntry);
                }
    
                leaderBoard.addAll(lowerEntries);
            }
        }
    
        return leaderBoard;
    }
    
    public void printBoard() {
    
        System.out.println("---------Start : Current leader board---------");
        leaderBoardUserEntryMap.forEach((key, value) -> {
            System.out.println("BOARD ENTRY : " + key + " : " + value);
        });
        System.out.println("---------End : Current leader board---------");
    }
    
    }
    
    public enum anagramgamefault{
    实例;
    私有地图排行榜UserEntryMap;
    {
    LeadboardUserEntryMap=新建LinkedHashMap();
    }
    public int calculateScore(字符串字、字符串字谜){
    if(word==null | | anagram==null){
    抛出新的NullPointerException(“单词和字谜都必须为非null”);
    }
    char[]wordArray=word.trim().toLowerCase().toCharArray();
    char[]anagramArray=anagram.trim().toLowerCase().tocharray();
    int[]alphabetCountArray=新int[26];
    int引用='a';
    for(int i=0;i(entry.getPosition()=upperPosition))
    .map(entry->new entry(entry.getUid()、entry.getScore()、entry.getPosition())
    .collect(Collectors.toList());
    //低分录
    lowerEntries=排行榜UserEntryMap.values().stream()
    .filter(条目->(entry.getPosition()>userPosition&&entry.getPosition()新条目(entry.getUid()、entry.getScore()、entry.getPosition())
    .collect(Collectors.toList());
    userEntry=新条目(userEntry.getUid(),userEntry.getScore(),userEntry.getPosition());
    // }
    if(higherEntries!=null&&!higherEntries.isEmpty()){
    if(higherEntries.size()>=MaxEntriesRoundanEntry){
    higherEntries=higherEntries.subList(higherEntries.size()-MaxEntriesRoundanEntry,
    higherEntries.size());
    }
    排行榜。添加所有(高级);
    }
    排行榜。添加(用户输入);
    if(lowerEntries!=null&&!lowerEntries.isEmpty()){
    if(lowerEntries.size()>=MaxEntriesRoundanEntry){
    lowerEntries=lowerEntries.子列表(0,MaxEntriesRoundanEntry);
    }
    排行榜。全部(低收入系列);
    }
    }
    返回排行榜;
    }
    公共印制板(){
    System.out.println(“-----------开始:当前领导板----------------”);
    排行榜UserEntryMap.forEach((键,值)->{
    System.out.println(“板项:“+key+”:“+value”);
    });
    System.out.println(“-----------结束:当前领导板-----------”);
    }
    }
    
  • 项目POJO:

    public class Entry implements Comparable<Entry> {
    
        private String uid;
        private int score;
        private int position;
    
        public Entry(String uid, int score) {
    
            this.uid = uid;
            this.score = score;
    
        }
    
        public Entry(String uid, int score, int position) {
    
            this.uid = uid;
            this.score = score;
            this.position = position;
        }
    
        public Entry() {
    
        }
    
        public String getUid() {
            return uid;
        }
    
        public void setUid(String uid) {
            this.uid = uid;
        }
    
        public int getScore() {
            return score;
        }
    
        public void setScore(int score) {
            this.score = score;
        }
    
        public int getPosition() {
            return position;
        }
    
        public void setPosition(int position) {
            this.position = position;
        }
    
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + score;
            result = prime * result + ((uid == null) ? 0 : uid.hashCode());
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Entry other = (Entry) obj;
            if (score != other.score)
                return false;
            if (uid == null) {
                if (other.uid != null)
                    return false;
            } else if (!uid.equals(other.uid))
                return false;
            return true;
        }
    
        @Override
        public String toString() {
            return "Entry [uid=" + uid + ", score=" + score + ", position=" + position + "]";
        }
    
        @Override
        public int compareTo(Entry o) {
            // TODO Auto-generated method stub
            if (o == null)
                return -1;
    
            return Integer.compare(score, o.getScore());
        }
    
    }
    
    公共类条目实现了可比较的{
    私有字符串uid;
    个人智力得分;
    私人职位;
    公共条目(字符串uid,整数分数){
    this.uid=uid;
    这个分数=分数;
    }
    公共条目(字符串uid、整数分数、整数位置){
    this.uid=uid;
    这个分数=分数;
    这个位置=位置;
    }
    公众进入(){
    }
    公共字符串getUid(){
    返回uid;
    }
    公共void setUid(字符串uid){
    this.uid=uid;
    }
    公共整数getScore(){
    返回分数;
    }
    
    public class AnagramGameDefaultDemo {
    
        public static void main(String[] args) {
    
            if (args == null || args.length < 1) {
                System.out.println("Enter testing approach - 1 for single threaded, 2 for multi-threaded");
                return;
            }
    
            switch (args[0]) {
    
            case "1": {
                new AnagramGameDefaultDemo().testSingleThreaded();
                break;
            }
    
            case "2": {
                new AnagramGameDefaultDemo().testMultithreaded();
                break;
            }
    
            default: {
                System.out.println("Enter proper option(1 or 2)");
                break;
            }
            }
    
        }
    
        private void testMultithreaded() {
    
            Map<String, String> stringAnagramMap = new HashMap<>();
    
            CountDownLatch countDownLatchOne = new CountDownLatch(1);
    
            stringAnagramMap.put("raw", "war");
            stringAnagramMap.put("raw", "wars");
            AnagramGamePlayer jake = new AnagramGamePlayer("jake", stringAnagramMap, countDownLatchOne);
            new Thread(jake, "jake").start();
    
            stringAnagramMap.clear();
    
            stringAnagramMap.put("tool", "loot");
            AnagramGamePlayer ace = new AnagramGamePlayer("ace", stringAnagramMap, countDownLatchOne);
            new Thread(ace, "ace").start();
    
            stringAnagramMap.clear();
    
            stringAnagramMap.put("William Shakespeare", "I am a weakish speller");
            AnagramGamePlayer max = new AnagramGamePlayer("max", stringAnagramMap, countDownLatchOne);
            new Thread(max, "max").start();
    
            stringAnagramMap.clear();
    
            stringAnagramMap.put("School master", "The classroom");
            AnagramGamePlayer tBone = new AnagramGamePlayer("tBone", stringAnagramMap, countDownLatchOne);
            new Thread(tBone, "tBone").start();
    
            stringAnagramMap.clear();
    
            countDownLatchOne.countDown();
    
            CountDownLatch countDownLatchTwo = new CountDownLatch(1);
    
            stringAnagramMap.put("Punishments", "Nine Thumps");
            AnagramGamePlayer razor = new AnagramGamePlayer("razor", stringAnagramMap, countDownLatchTwo);
            new Thread(razor, "razor").start();
    
            stringAnagramMap.clear();
    
            stringAnagramMap.put("Dormitory", "Dirty Room");
            AnagramGamePlayer chip = new AnagramGamePlayer("chip", stringAnagramMap, countDownLatchTwo);
            new Thread(chip, "chip").start();
    
            stringAnagramMap.clear();
    
            countDownLatchTwo.countDown();
    
            CountDownLatch countDownLatchThree = new CountDownLatch(1);
    
            stringAnagramMap.put("Mother in law", "Hitler woman");
            AnagramGamePlayer dale = new AnagramGamePlayer("dale", stringAnagramMap, countDownLatchThree);
            new Thread(dale, "dale").start();
    
            countDownLatchThree.countDown();
    
            stringAnagramMap.clear();
        }
    
        private final class AnagramGamePlayer implements Runnable {
    
            private Map<String, String> stringAnagramMap = new HashMap<>();
            private String uid;
            private CountDownLatch countDownLatch;
    
            public AnagramGamePlayer(String uid, Map<String, String> stringAnagramMap, CountDownLatch countDownLatch) {
                this.stringAnagramMap.putAll(stringAnagramMap);
                this.uid = uid;
                this.countDownLatch = countDownLatch;
            }
    
            @Override
            public void run() {
                AnagramGameDefault anagramGameDefault = AnagramGameDefault.INSTANCE;
    
                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
    
                System.out.println("Player " + uid + " started playing with " + stringAnagramMap);
                stringAnagramMap.entrySet().forEach(entry -> {
                    anagramGameDefault.submitScore(uid,
                            anagramGameDefault.calculateScore(entry.getKey(), entry.getValue()));
                    printLeaderBoard(uid, anagramGameDefault.getLeaderBoard(uid));
    
                });
    
                System.out.println("Player " + uid + " completed playing");
            }
    
        }
    
        private void testSingleThreaded() {
            AnagramGameDefault anagramGameDefault = AnagramGameDefault.INSTANCE;
            anagramGameDefault.submitScore("Jake", 3);
            anagramGameDefault.submitScore("Ace", 7);
            anagramGameDefault.submitScore("Max", 1);
            anagramGameDefault.submitScore("T-Bone", 14);
            anagramGameDefault.submitScore("Razor", 6);
            anagramGameDefault.submitScore("Razor", 7);
            anagramGameDefault.submitScore("He-Man", 4);
            anagramGameDefault.submitScore("Men-at-Arms", 8);
            anagramGameDefault.submitScore("BattleCat", 3);
            anagramGameDefault.submitScore("Jake", 2);
            anagramGameDefault.submitScore("BattleCat", 3);
            anagramGameDefault.printBoard();
    
            anagramGameDefault.submitScore("Men-at-Arms", 21);
            anagramGameDefault.submitScore("Orko", 20);
            anagramGameDefault.submitScore("Jake", 4);
            anagramGameDefault.printBoard();
    
            System.out.println();
            printLeaderBoard("user5", anagramGameDefault.getLeaderBoard("user5"));
            System.out.println();
            printLeaderBoard("user4", anagramGameDefault.getLeaderBoard("user4"));
            System.out.println();
            printLeaderBoard("user15", anagramGameDefault.getLeaderBoard("user15"));
            System.out.println();
            List<Entry> entries = anagramGameDefault.getLeaderBoard("user1");
            printLeaderBoard("user1", entries);
    
            System.out.println("Changing state of the received entries");
            entries.forEach(entry -> {
                entry.setPosition(1);
                entry.setScore(0);
            });
    
            anagramGameDefault.printBoard();
            printLeaderBoard("user1", anagramGameDefault.getLeaderBoard("user1"));
        }
    
        private static void printLeaderBoard(String user, List<Entry> leaderBoard) {
    
            if (user == null || leaderBoard.isEmpty()) {
                System.out.println("Either user " + user + " doesn't exist or leader board is empty " + leaderBoard);
            }
    
            System.out.println("**********Printing leader board for " + user);
            leaderBoard.forEach(System.out::println);
            System.out.println("**********");
        }
    
    }