ssm框架下多线程操作同一对象

时间:2022-07-25 18:31:05

前几天遇到这样一个问题,在ssm框架下如何让多个人对同一篇文章的同一个段落排队进行编辑,排队很容易就想到java中的queue队列,经过查阅才知道只要是框架它都会自动给你处理线程问题,每一个用户是一个线程,当用户从登录到点击某个文章进行编辑时,从进入这个系统开始整个系统就为这“一个”用户服务。

因为我发现,用户1点击进入某篇文章点击某个段落进行编辑时,队列只有一个用户1,但是当用户2同样点击某篇文章、点击同一段时,我发现队列又只有用户2了。就是说用户1线程进入系统时,系统只认识用户1,所有的资源只为用户1这个线程服务,用户2进入系统时,系统又只为用户2服务。如果不进行线程的处理那么就会造成这两个线程“目中无人”的现象。

刚开始错误想法如下:

Paragraph类聚合用户队列Queue

ssm框架下多线程操作同一对象
加入同步锁锁住文章读取出来的Para这个list,使每个用户线程往这个队列中插入时首先要协调各个线程,如下:
ssm框架下多线程操作同一对象
后来发现这个方法 并不好!
因为这个方法,只允许已经进入系统的线程进行同步,即用户1和用户2都在这个系统中,这时若用户3进入系统,系统会为用户3创建进程,用户3线程就会“看不见”用户2和用户1。
正确方法如下
给整个类用一个静态的Map存起来,Map里含有integer和另一个Map,Integer代表文章id,不仅能让一群人编辑文章1,还可以让另一群人编辑文章2,第二个map里又存入一个integer和queue,第二个integer用来存段落id,对应的值queue用来存储该段的用户队列。以下是构造这个静态Map的代码:
public static Map<Integer, Map<Integer, Queue<Long>>> map = new HashMap<Integer, Map<Integer, Queue<Long>>>();
    public static Map<Integer,List<Long>> onEditUsermap = new HashMap<>();  //用来存目前正在编辑的用户的map,integer代表文章,queue用来存用户
为了更直观,以下是我往这个map中插入文章id,以及用户所编辑的段落的id,以及如何往用户选择的段落对应的队列中插入用户id的代码:
//这个用来给相关用户插入相关段落的队列
    @PostMapping("insertqueue")
    public @ResponseBody Response<Boolean> insertqueue(@RequestBody ParaUserDTO paraUserDTO,HttpSession session){
        System.out.println("我在插入队列");
        List<Paragraph> para=(List<Paragraph>) session.getAttribute("para"); //将取出来的paraList的Object类型转成List<Paragraph>类型
        int docId=(int)session.getAttribute("docId");
        Boolean flag=false;  //用来记录是不是插入成功

        if (!map.containsKey(docId)){  //判断用户点击的这篇文章是不是已经有docId对应的记录
            Queue<Long> queue = new LinkedList<>();  //创建用户队列
            queue.offer(paraUserDTO.getUserId());   //队列里面插入用户的id
            Map<Integer,Queue<Long>> map1 = new HashMap<>();  //map1用来存放段落id以及用户队列
            map1.put(paraUserDTO.getDivId(),queue);  //map1放入段落id,以及段落对应的用户队列
            map.put(docId,map1);
            System.out.println(map.toString());
            flag=true;
        }
        else {   //如果有这篇文章的docId,那么就去找这篇文章的对应的段落
            Map<Integer,Queue<Long>> value=map.get(docId); //获取文章段落的那个对应map
            if(!value.containsKey(paraUserDTO.getDivId())){  //如果不包含用户申请的段落
                Queue<Long> queue=new LinkedList<>();
                queue.offer(paraUserDTO.getUserId());
                value.put(paraUserDTO.getDivId(),queue);  //把对应文章的部分加上这个文章段落和对应的队列
                System.out.println(map.toString());
                flag=true;
            }
            else{  //如果包含文章申请的段落,即仅仅只是在对应queue中插入用户id
                if (!value.get(paraUserDTO.getDivId()).contains(paraUserDTO.getUserId())){  //如果这个用户不在这个队列中
                    value.get(paraUserDTO.getDivId()).offer(paraUserDTO.getUserId()); //在队列后面添加一个用户
                    System.out.println(map.toString());
                    flag=true;
                }
                else{ //用户在这个队列中那就不做处理
                    flag=false;
                }

            }
        }
        return  Response.getSuccessResponse(flag);
    }
由于,map是静态的,所以是属于整个类的,对于map这个数据结构来说,程序run一次,那么这个结构只有一个,不管有多少线程,只要是操作这个map的语句,那么操作的资源仅此一个,所以以此实现多线程对同一个资源对象操作。 总结来说,各位如果想要某个数据结构在框架中仅此一个从而能让多线程对这个数据结构进行操作,那么不妨把这个数据结构设为静态static,把它构造在要用的类中。
小小普罗格瑞姆做的尝试,若有不足请指正。