FileLock类实现文件操作的并发访问

xiaoxiao2021-02-28  103

     今天在修改java web后端代码时想到了多用户并发访问问题,想到了文件操作时存在安全问题,所以学习了一下文件锁的使用。利用java的FileLock类控制不同程序的并发访问,实现文件同步。

    在java.nio包中提供了对文件的锁控制。主要是两个类,一个是FileChannel类,一个是FileLock类。FileLock类的作用是对FileChannel类进行实例化操作,而FileChannel类是对文件对象进行锁定。注意的是,文件锁对于一般的File类无效,想要使用文件锁需要以RandomAccessFile类创建文件对象。

注意点

1.锁类型:

共享锁: 共享读操作,但只能一个写(读可以同时,但写不能)。共享锁防止其他正在运行的程序获得重复的独占锁,但是允许他们获得重复的共享锁。只有一个读或一个写(读和写都不能同时)。独占锁防止其他程序获得任何类型的锁。

2.lock()和tryLock()的区别:

lock()阻塞的方法,锁定范围可以随着文件的增大而增加。无参lock()默认为独占锁;有参lock(0L, Long.MAX_VALUE, true)为共享锁。tryLock()非阻塞,当未获得锁时,返回null. 3.FileLock的生命周期: 在调用FileLock.release(),或者Channel.close(),或者JVM关闭

4.资源释放:

锁在被释放后才能被其他进程获得,通过release()方法释放,一般在用完文件后release()FileLock对象,close()FileChannel对象。文件锁的效果是与操作系统相关的,若想文件锁生效,则要保证其他程序也要按照API进行对文件访问。

代码使用

/** * class文件上传保存,同时管理表达式数据库新增、更新功能 * * @param file * @param request * @param response * @throws IOException * @throws JBOException * @throws InterruptedException */ @RequestMapping("craw/customFunctionUpload.do") public void fileUpload(@RequestParam(value = "classFile") MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws IOException, JBOException, InterruptedException { if (file != null) { String globalDir = request.getSession().getServletContext().getRealPath("/"); String fileName = file.getOriginalFilename(); String state = request.getParameter("state"); BizObjectManager bm = JBOFactory.getBizObjectManager("jbo.service.custom_function"); String version = "1"; int count = bm.createQuery("select count(*) from O where funcName=:funcName") .setParameter("funcName", fileName.substring(0, fileName.length() - 6)).getSingleResult(false) .getAttribute("count(*)").getInt(); // class文件新增上传 if ("0".equals(state)) { // 数据库中已存在同名表达式 if (count >= 1) { response.getWriter().print("{\"error\":\"已存在同名class!\"}"); return; } } // class文件更新上传 else { if (!fileName.substring(0, fileName.length() - 6).equals(state)) { response.getWriter().print("{\"error\":\"上传的class文件名与要修改的表达式名不匹配!\"}"); return; } if (count >= 1) { version = "" + (Integer .valueOf( bm.createQuery("select max(version) from O where funcName=:funcName") .setParameter("funcName", fileName.substring(0, fileName.length() - 6)) .getSingleResult(false).getAttribute("max(O.version)").getInt()) + 1); } } System.out.println(globalDir + "cfClasses/customfunction"); // 创建文件对象 File write = new File(globalDir + "cfClasses/files", fileName.substring(0, fileName.length() - 6) + "-" + version + ".class"); if (write.getParentFile().exists() == false) { System.out.println("dir not exist"); write.getParentFile().mkdirs(); } write.createNewFile(); // 保存文件 // 对该文件加锁 RandomAccessFile out = new RandomAccessFile(write, "rw"); FileChannel fcout = out.getChannel(); FileLock flout = null; while (true) { try { flout = fcout.tryLock(); break; } catch (Exception e) { System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒"); Thread.sleep(1000); } } InputStream ins = file.getInputStream(); // OutputStream ous = new FileOutputStream(write); try { byte[] buffer = new byte[1024]; ARE.getLog().debug("开始写文件:" + fileName); int len = 0; while ((len = ins.read(buffer)) > -1) out.write(buffer, 0, len); // ous.write(buffer, 0, len); ARE.getLog().debug("已保存的文件:" + fileName); } catch (Exception e) { response.getWriter().print("{\"error\":\"文件保存失败\"}"); } finally { ins.close(); } //将存储文件临时拷贝到com.amarsoft.custom.function包下解析 File write2 = new File(globalDir + "cfClasses/com/amarsoft/custom/function", fileName); if (write2.getParentFile().exists() == false) { System.out.println("dir not exist"); write2.getParentFile().mkdirs(); } write2.createNewFile(); //加锁 RandomAccessFile out2 = new RandomAccessFile(write2, "rw"); FileChannel fcout2 = out2.getChannel(); FileLock flout2 = null; while (true) { try { flout2 = fcout2.tryLock(); break; } catch (Exception e) { System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒"); Thread.sleep(1000); } } ins = file.getInputStream(); try { byte[] buffer = new byte[1024]; // ARE.getLog().debug("开始写文件:" + fileName); int len = 0; while ((len = ins.read(buffer)) > -1) out2.write(buffer, 0, len); // ARE.getLog().debug("已保存的文件:" + fileName); } catch (Exception e) { write.delete(); flout.release(); fcout.close(); out.close(); out = null; response.getWriter().print("{\"error\":\"文件保存失败\"}"); return; } finally { ins.close(); flout2.release(); fcout2.close(); out2.close(); out2 = null; flout.release(); fcout.close(); out.close(); out = null; } // 解析class文件,查看是否存在方法名为“action”的方法 String funcTemplateName = fileName.substring(0, fileName.length() - 6); String funcTemplate = funcTemplateName + "("; Map<String,Class> map = (Map<String, Class>) request.getSession().getServletContext().getAttribute("ClassMap"); synchronized(map){ //Class toDel = map.get(funcTemplateName); FileClassLoader fileClsLoader = new FileClassLoader(); fileClsLoader.setClassPath(globalDir + "cfClasses"); // class文件中存在方法名为action的方法的标志 boolean flag = false; int paramCount = 0; String runFunc = "action"; Class cls = null; try { cls = fileClsLoader .loadClass("com.amarsoft.custom.function." + fileName.substring(0, fileName.length() - 6)); Method[] mthds = cls.getMethods(); for (Method mthd : mthds) { String methodName = mthd.getName(); if (methodName.equals(runFunc)) { flag = true; paramCount = mthd.getGenericParameterTypes().length; for (int i = 1; i <= paramCount; i++) { funcTemplate += "${" + i + "},"; } if (paramCount > 0) { funcTemplate = funcTemplate.substring(0, funcTemplate.length() - 1); } funcTemplate += ")"; } } } catch (Exception e) { ARE.getLog().error("解析class文件模板函数失败!", e); write.delete(); cls = null; fileClsLoader = null; response.getWriter().print("{\"error\":\"文件保存失败\"}"); } finally { write2.delete(); System.out.println("write2 deleted!"); } if (!flag) { write.delete(); response.getWriter().print("{\"error\":\"class文件中不存在方法名为" + runFunc + "的方法\"}"); return; } if(cls != null) { map.put(funcTemplateName, cls); cls = null; fileClsLoader = null; } } BizObject obj = bm.newObject(); obj.setAttributeValue("funcName", fileName.substring(0, fileName.length() - 6)); obj.setAttributeValue("funcTemplate", funcTemplate); obj.setAttributeValue("version", version); obj.setAttributeValue("inputTime", StringFunction.getTodayNow()); obj.setAttributeValue("updateTime", StringFunction.getTodayNow()); bm.saveObject(obj); response.getWriter().print("{}"); } else { System.out.println("file empty"); response.getWriter().print("{\"error\":\"上传失败\"}"); } }

参考文章

http://blog.csdn.net/wangbaochu/article/details/48546717 http://blog.csdn.net/gxy3509394/article/details/7435993

转载请注明原文地址: https://www.6miu.com/read-56203.html

最新回复(0)