相关文章推荐
慷慨的抽屉  ·  C# ...·  1 月前    · 
奔放的针织衫  ·  WPF:解决 ...·  1 月前    · 
纯真的冲锋衣  ·  数据争用(data race) ...·  1 月前    · 
体贴的蘑菇  ·  DownloadsFolder 类 ...·  1 年前    · 
安静的小刀  ·  Io 异常: The Network ...·  1 年前    · 

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() {
                            @Override
                            public void onCompleted(Object result) {
                            @Override
                            public void onLoading(Object readedPart, long current, long length) {
                            @Override
                            public void onInterrupted() {
                            @Override
                            public void onFail(String errorMsg) {

读文件使用示例

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

各位老铁有问题欢迎及时联系、指正、批评、撕逼

Github:
https://github.com/AnJiaoDe
简书:
https://www.jianshu.com/u/b8159d455c69

微信公众号

NIO提升性能在JAVA的标准I/O中,提供了基于流的I/O实现,即InputStream和OutputStream。这种基于流的实现以字节为单位处理数据。NIO是New I/O的简称,表示一套新的JAVA I/O标准。在Jdk 1.4中开始引入,它具有以下特性:为所有的原始类型提供(Buffer)缓存支持; 使用Java.nio.charset.Charset作为字符集编...
文章目录Java文件系统java.ioFileInputStream & FileOutputStream对输入输出流方向的理解RandomAccessFilejava.nio.file.Files完 Java文件系统 Java内置两种文件系统:阻塞模式io和非阻塞模式nio java.io Java的有许多读取文件的方法,如java.io.FileReader,但基本上都是封装了java.io.FileInputStream类;写文件也是基本上封装java.io.FileOutputStream
importjava.io.File; importjava.io.FileInputStream; importjava.io.FileOutputStream; importjava.io.OutputStream; ...
Java多线程方式复制文件**这几日有一个数据迁移需求,是说从一个系统中将所有的图片按照新的规则迁移到新的系统中来。** 思路如下1. 使用生产者模式将要下载的清单放到一个阻塞队列里面。 2. 执行消费者模式读取文件并进行处理。 其核心代码如下生产者//生产者 import java.util.concurrent.BlockingQueue; public class Producer imple
 1.如何用file操作目录和文件java对待目录和文件统一使用file来表示,在创建file对象时,使用isDictionary和isFile方法进行判断 1 package test; 3 import java.io.File; 5 import java.io.IOException; 7 public class FileTest { 序列化: Serialiaze 将java对象转换为二进制流ObjectOutputStream .writeObject(java对象) 反序列化: 二进制流还原java对象ObjectInputStream .readObject() --> java对象 java中要支持序列化和反序列化,需要实现接口Serializable(标记接口) seriaVersionUID序列化版本(序列号) 当对class类做修改时,seriaVersionUID就会变动,反序列化时就会报异常,可以把
Java 中,多线程操作文件可以通过多种方式实现。一种常见的方法是使用 Java 内置的 java.nio 包中的类,如 FileChannel 和 MappedByteBuffer 等。 如果要以多线程的方式读取或写入文件,您可以创建多个线程,每个线程都负责读取或写入一个文件的一个特定部分。这样可以提高处理文件的速度,因为多个线程可以并行执行读写操作。 但是,在使用多线程读写文件时,需要注意并发访问问题,以防止多个线程同时写入同一个文件,从而造成文件破坏。因此,通常需要使用同步代码块或线程等机制来保证并发读写安全性。
CSDN-Ada助手: 嗨~好久未见你更新博文了,我们现在上线了AI创作助手哦~可为你的创作提供智能化帮助,快来试试吧~https://editor.csdn.net/md/?not_checkout=1&utmsource=blog_comment_recall,在编辑器页面右侧哦~~限免!! 同时我们为您准备了一份回归奖励,快来看看吧https://activity.csdn.net/creatActivity?id=10430&utmsource=blog_comment_recall Docker无法启动 error initializing graphdriver: driver not supported Gavin_kkkk: 可以,我的可以,非常感谢表情包 一个字母占几个字节 南南很难: char类型在C或C++中占1个字节,在java中占2个字节。 sudo netstat -nltp 菜码代码: 这表示用root查看进程吗