文章目录

  • NIO提升性能
  • 多线程读写同一个文件有哪些场景需要同步处理?
  • 使用对文件加锁的方式做到线程安全
  • 写文件线程安全
  • 读文件线程安全
  • 小编写的IOListener接口,用于回调
  • 小编写的IOUtils工具类,专门用于文件读写,流的读写
  • 写文件使用示例
  • 读文件使用示例
  • 欢迎联系、指正、批评

NIO提升性能

在JAVA的标准I/O中,提供了基于流的I/O实现,即InputStream和OutputStream。这种基于流的实现以字节为单位处理数据。NIO是New I/O的简称,表示一套新的JAVA I/O标准。在Jdk 1.4中开始引入,它具有以下特性:

  • 为所有的原始类型提供(Buffer)缓存支持;
  • 使用Java.nio.charset.Charset作为字符集编码解码解决方案;
  • 增加通道(Cahnnel)对象,作为新的原始I/O抽象;
  • 支持锁和内存映射文件的文件访问接口;
  • 提供了基于Selector的异步网络I/O。

与流式的I/O不容,NIO是基于块(Block)的,它以块为基本单位处理数据。在NIO中,最为重要的2个组件是缓冲Buffer和通道Channel。缓冲是一块连续的内存块,是NIO读写数据的中转地。通道表示缓冲数据的源头或者目的地,它用于向缓冲读取或者写入数据,是访问缓冲的接口。

多线程读写同一个文件有哪些场景需要同步处理?

  • 有线程正在读文件,另开辟线程写文件;
  • 有线程正在写文件,另开辟线程读文件;
  • 有线程正在写文件,另开辟线程写文件

总之,读写互斥,写读互斥,写写互斥,只有读读相容(可以异步)。

使用对文件加锁的方式做到线程安全

FileInputStream、FileOutputStream、RandomAccessFile均可得到FileChannel对象,对文件锁进行操作。
独占锁tryLock()

FileChannel的tryLock()是非阻塞的,也就是说,在发现文件被锁住的时候,直接返回null,并且抛出异常,如果没有锁住,直接返回该文件的文件锁。
它是独占锁,就是只能被一个线程持有,它能禁止其他线程获取共享锁,可用于写文件。

  while (true) {try {fileLock = fileChannel.tryLock();//独占锁break;} catch (Exception e) {System.out.println("有其他线程正在操作该文件,当前线程" + Thread.currentThread().getName());}}

共享锁tryLock(0, Long.MAX_VALUE, true)

FileChannel的tryLock(0, Long.MAX_VALUE, true)是非阻塞的,在发现文件被锁住的时候,直接返回null,并且抛出异常,如果没有锁住,直接返回该文件的文件锁。
它是共享锁,能被多个线程同时持有,它能禁止其他线程获取独占锁,可用于读文件。

while (true) {try {fileLock = fileChannel.tryLock(0, Long.MAX_VALUE, true);//共享锁break;} catch (Exception e) {System.out.println("有其他线程正在操作该文件,当前线程" + Thread.currentThread().getName());}}

独占锁lock()

而FileChannel的lock()是阻塞的,在文件被锁定的情况下,会保持阻塞,直到获得该锁为止。

fileLock = fileChannel.lock();

写文件线程安全

 /*** 将str写入文件,同步操作,独占锁*/public void writeStr2ReplaceFileSync(String str, String pathFile, IOListener ioListener) {File file;try {file = FileUtils.createFile(pathFile);} catch (IOException e) {e.printStackTrace();ioListener.onFail("文件创建失败,请检查路径是否合法以及读写权限");return;}FileOutputStream fileOutputStream = null;FileChannel fileChannel = null;FileLock fileLock = null;//文件锁try {/*** 写文件*/fileOutputStream = new FileOutputStream(file);fileChannel = fileOutputStream.getChannel();while (true) {try {fileLock = fileChannel.tryLock();//独占锁break;} catch (Exception e) {System.out.println("有其他线程正在操作该文件,当前线程" + Thread.currentThread().getName());}}if (fileLock != null) {int len = 0;long current = file.length();if (isRunning ) {fileChannel.write(ByteBuffer.wrap(str.getBytes()));current += len;LogUtils.log("当前线程" + Thread.currentThread().getName());ioListener.onLoading(str.getBytes(), current, str.length());}else {//中断ioListener.onInterrupted();}if (fileLock != null && fileLock.isValid()) {LogUtils.log("release-write-lock");fileLock.release();}close(fileChannel);close(fileOutputStream);if (file.length() == str.getBytes().length) {ioListener.onCompleted(file);}}} catch (IOException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} finally {}}

读文件线程安全

  /*** 同步读取,共享锁,但无法同时进行写操作** @param ioListener*/public void read2StrSync(String pathFile, IOListener ioListener) {FileInputStream fileInputStream = null;FileChannel fileChannel = null;FileLock fileLock = null;//文件锁ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();try {/*** 读文件*/fileInputStream = new FileInputStream(pathFile);fileChannel = fileInputStream.getChannel();while (true) {try {fileLock = fileChannel.tryLock(0, Long.MAX_VALUE, true);//共享锁break;} catch (Exception e) {System.out.println("有其他线程正在操作该文件,当前线程" + Thread.currentThread().getName());}}if (fileLock != null) {ByteBuffer byteBuffer = ByteBuffer.allocate(1024);int len = 0;long current = 0;while (isRunning && (len = fileChannel.read(byteBuffer)) != -1) {//0,byteBuffer.position(),必须写这个,否则GG,读取文件错乱byteArrayOutputStream.write(byteBuffer.array(),0,byteBuffer.position());current += len;ioListener.onLoading("", current, fileChannel.size());byteBuffer.clear();}if (fileLock != null && fileLock.isValid()) {LogUtils.log("release-read-lock");fileLock.release();}close(fileChannel);close(fileInputStream);//中断if (len != -1) {ioListener.onInterrupted();} else {ioListener.onCompleted(byteArrayOutputStream.toString("utf-8"));}}} catch (UnsupportedEncodingException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} catch (IOException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} finally {}}

小编写的IOListener接口,用于回调

public interface IOListener<T> {public void onCompleted(T result);public void onLoading(T readedPart, long current, long length);public void onInterrupted();public void onFail(String errorMsg);
}

小编写的IOUtils工具类,专门用于文件读写,流的读写

public class IOUtils {private boolean isRunning = true;private long contentLength = 0;private String encodeType = "utf-8";public IOUtils() {isRunning = true;}public IOUtils setContentLength(long contentLength) {this.contentLength = contentLength;return this;}public IOUtils setEncodeType(String encodeType) {this.encodeType = encodeType;return this;}public static void close(Closeable closeable) {if (closeable != null) {try {closeable.close();} catch (IOException e) {e.printStackTrace();}}}public void stop() {this.isRunning = false;}public void read(boolean isLine, InputStream inputStream, IOListener ioListener) {if (isLine) {readLine2String(inputStream, ioListener);} else {read2String(inputStream, ioListener);}}/*** @param ioListener*/public void read2String(String pathFile, IOListener ioListener) {FileInputStream fileInputStream = null;try {fileInputStream = new FileInputStream(pathFile);} catch (FileNotFoundException e) {e.printStackTrace();ioListener.onFail(e.getMessage());return;}read2String(fileInputStream, ioListener);}public void read2String(InputStream inputStream, IOListener ioListener) {if (!(inputStream instanceof BufferedInputStream)) {inputStream = new BufferedInputStream(inputStream);}BufferedReader bufferedReader = null;InputStreamReader inputStreamReader = null;try {inputStreamReader = new InputStreamReader(inputStream, encodeType);bufferedReader = new BufferedReader(inputStreamReader);StringBuilder sb = new StringBuilder();char[] buf = new char[1024];int len = 0;long current = 0;while (isRunning && (len = bufferedReader.read(buf)) != -1) {sb.append(buf, 0, len);current += len;ioListener.onLoading("", current, contentLength);}//中断if (len != -1) {ioListener.onInterrupted();} else {ioListener.onCompleted(sb.toString());}} catch (UnsupportedEncodingException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} catch (IOException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} finally {close(bufferedReader);close(inputStreamReader);close(inputStream);}}/*** 同步读取,共享锁,但无法同时进行写操作** @param ioListener*/public void read2StrSync(String pathFile, IOListener ioListener) {FileInputStream fileInputStream = null;FileChannel fileChannel = null;FileLock fileLock = null;//文件锁ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();try {/*** 读文件*/fileInputStream = new FileInputStream(pathFile);fileChannel = fileInputStream.getChannel();while (true) {try {fileLock = fileChannel.tryLock(0, Long.MAX_VALUE, true);//共享锁break;} catch (Exception e) {System.out.println("有其他线程正在操作该文件,当前线程" + Thread.currentThread().getName());}}if (fileLock != null) {ByteBuffer byteBuffer = ByteBuffer.allocate(1024);int len = 0;long current = 0;while (isRunning && (len = fileChannel.read(byteBuffer)) != -1) {//0,byteBuffer.position(),必须写这个,否则GG,读取文件错乱byteArrayOutputStream.write(byteBuffer.array(),0,byteBuffer.position());current += len;ioListener.onLoading("", current, fileChannel.size());byteBuffer.clear();}if (fileLock != null && fileLock.isValid()) {LogUtils.log("release-read-lock");fileLock.release();}close(fileChannel);close(fileInputStream);//中断if (len != -1) {ioListener.onInterrupted();} else {ioListener.onCompleted(byteArrayOutputStream.toString("utf-8"));}}} catch (UnsupportedEncodingException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} catch (IOException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} finally {}}/*** @param ioListener*/public void readLine2String(String pathFile, IOListener ioListener) {FileInputStream fileInputStream = null;try {fileInputStream = new FileInputStream(pathFile);} catch (FileNotFoundException e) {e.printStackTrace();ioListener.onFail(e.getMessage());return;}readLine2String(fileInputStream, ioListener);}/*** 一行一行地读** @param inputStream* @param ioListener*/public void readLine2String(InputStream inputStream, IOListener ioListener) {BufferedReader bufferedReader = null;InputStreamReader inputStreamReader = null;try {inputStreamReader = new InputStreamReader(inputStream, encodeType);bufferedReader = new BufferedReader(inputStreamReader);StringBuilder sb = new StringBuilder();long current = 0;String str;while (isRunning && (str = bufferedReader.readLine()) != null) {sb.append(str);current += str.length();ioListener.onLoading(str, current, contentLength);}//中断if ((str = bufferedReader.readLine()) != null) {ioListener.onInterrupted();} else {ioListener.onCompleted(sb.toString());}} catch (UnsupportedEncodingException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} catch (IOException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} finally {close(bufferedReader);close(inputStreamReader);close(inputStream);}}public void readL2StrNoBuffer(String pathFile, IOListener ioListener) {FileInputStream fileInputStream = null;try {fileInputStream = new FileInputStream(pathFile);} catch (FileNotFoundException e) {e.printStackTrace();ioListener.onFail(e.getMessage());return;}readL2StrNoBuffer(fileInputStream, ioListener);}/*** 一行一行地读,不拼接** @param inputStream* @param ioListener*/public void readL2StrNoBuffer(InputStream inputStream, IOListener ioListener) {BufferedReader bufferedReader = null;InputStreamReader inputStreamReader = null;try {inputStreamReader = new InputStreamReader(inputStream, encodeType);bufferedReader = new BufferedReader(inputStreamReader);long current = 0;String str;while (isRunning && (str = bufferedReader.readLine()) != null) {current += str.length();ioListener.onLoading(str, current, contentLength);}//中断if ((str = bufferedReader.readLine()) != null) {ioListener.onInterrupted();} else {ioListener.onCompleted("");}} catch (UnsupportedEncodingException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} catch (IOException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} finally {close(bufferedReader);close(inputStreamReader);close(inputStream);}}public void readL_N2String(String pathFile, IOListener ioListener) {FileInputStream fileInputStream = null;try {fileInputStream = new FileInputStream(pathFile);} catch (FileNotFoundException e) {e.printStackTrace();ioListener.onFail(e.getMessage());return;}readL_N2String(fileInputStream, ioListener);}/*** 一行一行地读,\n拼接** @param inputStream* @param ioListener*/public void readL_N2String(InputStream inputStream, IOListener ioListener) {BufferedReader bufferedReader = null;InputStreamReader inputStreamReader = null;try {inputStreamReader = new InputStreamReader(inputStream, encodeType);bufferedReader = new BufferedReader(inputStreamReader);StringBuilder sb = new StringBuilder();long current = 0;String str;while (isRunning && (str = bufferedReader.readLine()) != null) {sb.append(str);sb.append("\n");current += str.length();ioListener.onLoading(str, current, contentLength);}//中断if ((str = bufferedReader.readLine()) != null) {ioListener.onInterrupted();} else {ioListener.onCompleted(sb.toString());}} catch (UnsupportedEncodingException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} catch (IOException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} finally {close(bufferedReader);close(inputStreamReader);close(inputStream);}}/*** 读取到文件** @param inputStream* @param outputStream* @param ioListener*/public void read2File(InputStream inputStream, OutputStream outputStream, IOListener ioListener) {try {byte[] buffer = new byte[1024];int len = 0;long current = 0;while (isRunning && (len = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, len);current += len;ioListener.onLoading(new String(buffer), current, contentLength);}outputStream.flush();//中断if (len != -1) {ioListener.onInterrupted();} else {ioListener.onCompleted(null);}} catch (IOException e) {e.printStackTrace();} finally {close(outputStream);close(inputStream);}}/*** 将str写入文件*/public void writeStr2File(String str, String pathFile, IOListener ioListener) {BufferedWriter bufferedWriter = null;OutputStreamWriter outputStreamWriter = null;OutputStream outputStream = null;try {outputStream = new FileOutputStream(pathFile);outputStreamWriter = new OutputStreamWriter(outputStream);bufferedWriter = new BufferedWriter(outputStreamWriter);bufferedWriter.write(str);ioListener.onCompleted("");} catch (IOException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} finally {close(bufferedWriter);close(outputStreamWriter);close(outputStream);}}/*** 将str写入文件,同步操作,独占锁*/public void writeStr2ReplaceFileSync(String str, String pathFile, IOListener ioListener) {File file;try {file = FileUtils.createFile(pathFile);} catch (IOException e) {e.printStackTrace();ioListener.onFail("文件创建失败,请检查路径是否合法以及读写权限");return;}FileOutputStream fileOutputStream = null;FileChannel fileChannel = null;FileLock fileLock = null;//文件锁try {/*** 写文件*/fileOutputStream = new FileOutputStream(file);fileChannel = fileOutputStream.getChannel();while (true) {try {fileLock = fileChannel.tryLock();//独占锁break;} catch (Exception e) {System.out.println("有其他线程正在操作该文件,当前线程" + Thread.currentThread().getName());}}if (fileLock != null) {int len = 0;long current = file.length();if (isRunning ) {fileChannel.write(ByteBuffer.wrap(str.getBytes()));current += len;LogUtils.log("当前线程" + Thread.currentThread().getName());ioListener.onLoading(str.getBytes(), current, str.length());}else {//中断ioListener.onInterrupted();}if (fileLock != null && fileLock.isValid()) {LogUtils.log("release-write-lock");fileLock.release();}close(fileChannel);close(fileOutputStream);if (file.length() == str.getBytes().length) {ioListener.onCompleted(file);}}} catch (IOException e) {e.printStackTrace();ioListener.onFail(e.getMessage());} finally {}}}

写文件使用示例

 new IOUtils().writeStr2ReplaceFileSync(jsonObjectOld.toJSONString(), Constants.PATH_GAME_JSON, new IOListener() {@Overridepublic void onCompleted(Object result) {}@Overridepublic void onLoading(Object readedPart, long current, long length) {}@Overridepublic void onInterrupted() {}@Overridepublic void onFail(String errorMsg) {}});

读文件使用示例

new IOUtils().read2StrSync(Constants.PATH_CONFIG_APPLICATION_JSON, new IOListener<String>() {@Overridepublic void onCompleted(String result) {}@Overridepublic void onLoading(String readedPart, long current, long length) {}@Overridepublic void onInterrupted() {}@Overridepublic void onFail(String errorMsg) {}});

欢迎联系、指正、批评

Github:https://github.com/AnJiaoDe

CSDN:https://blog.csdn.net/confusing_awakening

OpenCV入门教程:https://blog.csdn.net/confusing_awakening/article/details/113372425

ffmpeg入门教程:https://blog.csdn.net/confusing_awakening/article/details/102007792

微信公众号

QQ群

JAVA多线程读写文件如何做到线程安全?(文件锁,FileChannel)相关推荐

  1. python 多线程读写文件_Python多线程同步---文件读写控制方法

    1.实现文件读写的文件ltz_schedule_times.py #! /usr/bin/env python #coding=utf-8 import os def ReadTimes(): res ...

  2. Java多线程下载文件

    Java多线程下载文件 优化:合理利用服务器资源,将资源利用最大化,加快下载速度 一般有两种方式: 线程池里面有N个线程,多线程下载单个文件,将网络路径的文件流切割成多快,每个线程下载一小部分,然后写 ...

  3. python 多线程读写文件_python多线程同步之文件读写控制

    本文实例为大家分享了python多线程同步之文件读写控制的具体代码,供大家参考,具体内容如下 1.实现文件读写的文件ltz_schedule_times.py #! /usr/bin/env pyth ...

  4. Java多线程编程-(4)-线程间通信机制的介绍与使用

    上一篇: Java多线程编程-(1)-线程安全和锁Synchronized概念 Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性 Java多线程编程-(3)-线程本地Th ...

  5. java线程带来的异常,java多线程练习之捕获子线程异常例子

    本文章给大家介绍java多线程练习之捕获子线程异常一个实例,希望对大家会有所帮助. java多线程程序中,所有线程都不允许抛出未捕获的checked exception,也就是说各个线程需要自己把自己 ...

  6. java(IO)读写文件乱码转换UTF-8问题

    java(IO)读写文件乱码转换UTF-8问题 读取文件String Content = ""; // 文件很长的话建议使用StringBuffertry {FileInputSt ...

  7. Java多线程学习(八)线程池与Executor 框架

    历史优质文章推荐: Java并发编程指南专栏 分布式系统的经典基础理论 可能是最漂亮的Spring事务管理详解 面试中关于Java虚拟机(jvm)的问题看这篇就够了 目录: [TOC] 本节思维导图: ...

  8. java多线程读取文件_java多线程读写同一个文件

    本文提供java多线程分别定时读写同一个文件的样例,其中两个线程,一个每分钟写入当前时间到指定文件,另一个线程读出每分钟新写的内容. 使用简单的Thread.sleep技术实现定时 package t ...

  9. java 多线程编程(包括创建线程的三种方式、线程的生命周期、线程的调度策略、线程同步、线程通信、线程池、死锁等)

    1 多线程的基础知识 1.1 单核CPU和多核CPU 单核CPU,其实是一种假的多线程,因为在一个时间单元内,也只能执行一个线程的任务.微观上这些程序是分时的交替运行,只不过是给人的感觉是同时运行,那 ...

最新文章

  1. python面向对象重新梳理
  2. warning:partition X does not end on cylinder boundary
  3. 2008台北英特尔信息技术峰会主题演讲精选-王文汉
  4. [分享]技术改进方案模板
  5. gdb 查看,执行汇编代码
  6. 网站特效-------旋转的图片
  7. 米拓建站系统(MetInfo CMS)文章定时发布软件
  8. 国家市场监管总局:互联网广告不得等倒计时结束才能关闭
  9. php 判断数组某个值,浅谈PHP检查数组中是否存在某个值 in_array 函数
  10. TypeScript算法专题 - blog1.基于TypeScript语言的单链表实现
  11. c语言循环语句解鸡兔同笼,JavaScript的for循环语句练习之解决鸡兔同笼问题
  12. 4、keygen激活secureCRT
  13. Excel合并单元格读取
  14. iptv登录系统 无法连接服务器,电信宽带电视连接到83%接入平台进不去什么情况-网络电视接入平台失败...
  15. 微信小程序 canvas 分享图片 生成图片
  16. python 学生信息管理系统(二)
  17. 麻辣隔壁的我的C币被盗了!?
  18. 【sql查询】使用sql查询一个物品是否在有效期内的方法(数据库无这个字段 通过生产日期和保质期进行计算得出)
  19. Sinvoice:创新声波通信技术,给您带来全新的连接体验!
  20. python中find是什么意思啊_python中str的find()

热门文章

  1. python解题教学设计的理解_面向计算思维培养的初中 Python 项目式学习教学设计流程构建...
  2. 极智AI | 目标检测实现分享二:听说克莱今天复出了?详解 YOLOv2 算法与克莱检测
  3. 如何进行测试用例评审
  4. 面试了一位 阿里出来的46 岁的程序员,思绪万千,最后结局居然...
  5. Windows下用命令行注销用户(包括注销其他用户)
  6. 开源在线excel编辑器_推荐3款爽到爆的在线网站
  7. 科大讯飞语音无限制录音、识别功能的实现:Android studio(一)
  8. HMACSHA加密方法
  9. 操作系统分类及Linux
  10. 多人扑克游戏:99分游戏规则介绍