900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > JAVA多线程读写文件如何做到线程安全?(文件锁 FileChannel)

JAVA多线程读写文件如何做到线程安全?(文件锁 FileChannel)

时间:2024-05-23 10:18:35

相关推荐

JAVA多线程读写文件如何做到线程安全?(文件锁 FileChannel)

文章目录

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:/AnJiaoDe

CSDN:/confusing_awakening

OpenCV入门教程:/confusing_awakening/article/details/113372425

ffmpeg入门教程:/confusing_awakening/article/details/10792

微信公众号

QQ群

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。