此方法为什么会有并发问题?已加锁,依然会有并发覆盖,(出错位置为,多个线程操作同一Session)
(该方法功能为文件分片创建临时文件对象,并将文件对象保存到当前session中,以便于分片合并,问题出在当流程走chunks分支,操作session时会出现并发问题;当加锁时,应当会锁住当前对象;这个方法实现类取自springmvc容器,为单例对象,理论上同一时刻只会有一个线程才能取得这个锁,个人理解应当不会出现并发问题,不知道是不是哪个地方没有想到?希望高人指点
flag含义:chunks:为分片创建文件;single:为单文件(不需要切片)创建文件,merging:为合并分片创建文件;tempWorkPath:分片临时保存目录地址;saveFilePath:最终文件保存地址)
@Override synchronized public File GenerateDirPathForCurrFile(MutilFileInfo fileinfo,String flag) throws Exception { String fileName = fileinfo.getName(); String lastModifiedDate = fileinfo.getLastModifiedDate(); String fileSize = fileinfo.getSize(); String type = fileinfo.getType(); String id = fileinfo.getId(); long timeStemp=System.currentTimeMillis(); if("single".equals(flag)||"merging".equals(flag)) { String extName = fileName.substring(fileName.lastIndexOf(".")); String fileNameSource = fileName+lastModifiedDate+fileSize+type+id+timeStemp; String fileDirName = SHA256Util.getSHA256StrJava(fileNameSource)+extName; File targetFile = new File(saveFilePath,fileDirName); while(targetFile.exists()){ fileNameSource=fileNameSource+"1"; fileDirName = SHA256Util.getSHA256StrJava(fileNameSource)+extName; targetFile = new File(fileDirName); } return targetFile; }else if("chunks".equals(flag)) { String fileNameSource = tempWorkPath+"/"+timeStemp+"_"+fileName+"_"+"part"+fileinfo.getChunk(); File tempFile = new File(fileNameSource); fileinfo.setFileChunk(tempFile); if(SessionUtils.getSessionAttribute("fileChunks")==null){ //fileChunksMapLock.lock();//此处加锁,防止并发创建时fileChunks中数据被覆盖 if(SessionUtils.getSessionAttribute("fileChunks")==null){ ConcurrentHashMap<String, Object> fileChunksMap = new ConcurrentHashMap<>(); SessionUtils.setSessionAttribute("fileChunks", fileChunksMap); System.out.println("创建fileChunksMaps=========="); } //fileChunksMapLock.unlock();//释放锁 } ConcurrentHashMap<String, Object> fileChunksMap = (ConcurrentHashMap<String, Object>) SessionUtils.getSessionAttribute("fileChunks"); if(fileChunksMap.get(id+fileName)==null){ //chunksArrLock.lock();//此处加锁,防止并发创建时chunksArr中数据被覆盖 if(fileChunksMap.get(id+fileName)==null){ //MutilFileInfo[] chunksArr = new MutilFileInfo[fileinfo.getChunks()]; List<MutilFileInfo> chunksArr=Collections.synchronizedList(new ArrayList<>()); fileChunksMap.put(id+fileName, chunksArr); System.out.println("创建fileChunksArr=========="); } //chunksArrLock.unlock();//释放锁 } @SuppressWarnings("unchecked") List<MutilFileInfo> chunksArr = (List<MutilFileInfo>) fileChunksMap.get(id+fileName); chunksArr.add(fileinfo); System.out.println("添加fileinfo:"+fileinfo); return tempFile; }else{ throw new Exception("目标文件生成失败"); } }
问题现已解决,原因是前端jsessionId不一致造成的,前端并发提交时造成jsessionId覆盖,同时springboot2默认开启httpOnly也有点影响,后台线程同步那一块没有问题。
if(SessionUtils.getSessionAttribute("fileChunks")==null){
ConcurrentHashMap<String, Object> fileChunksMap = new ConcurrentHashMap<>();
SessionUtils.setSessionAttribute("fileChunks", fileChunksMap);
System.out.println("创建fileChunksMaps==========");
}
System.out.println("SessionUtils.getSessionAttribute-fileChunks" + SessionUtils.getSessionAttribute("fileChunks"));
你先下个main函数,测下如上代码,然后我看下结果;
问题现已解决,原因是前端jsessionId不一致造成的,前端并发提交时造成jsessionId覆盖,同时springboot2默认开启httpOnly也有点影响,后台线程同步那一块没有问题。
首先确认下你这个从spring获取的对象真的是单例??按理说能并发说明拿到的锁不是同一个,你把代码修改为,锁代码块 ~加上 synchronized (this)试试~
问题现已解决,原因是前端jsessionId不一致造成的,前端并发提交时造成jsessionId覆盖,同时springboot2默认开启httpOnly也有点影响,后台线程同步那一块没有问题。
对博客园的结帖机制有点懵逼,没有选择最佳答案,但园豆是默认给了第一楼,希望二楼的兄弟不要见怪哈!