第三方 commons-io 线程安全吗?

FileUtils类的方法,写文件时是否线程安全?比如:

FileUtils.writeStringToFile(new File("/home/test1/d.txt"), "1\n", "utf-8",true);

我追踪代码,发现该方法调用FileOutputStream的native方法:

private native void writeBytes(byte b[], int off, int len, boolean append)
        throws IOException;

没见到锁。下面的1000个并发写文件,也没出现数据不一致

public static void multiple() throws InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(100);
        
        ArrayList<Callable<Integer>> arrayList = new ArrayList<Callable<Integer>>();
        
        for (int i = 0; i < 1000; i++) {
            arrayList.add(()->{
                FileUtils.writeStringToFile(new File("/home/test1/d.txt"), "1\n", "utf-8",true);
                return 1;
            });
        }
        pool.invokeAll(arrayList);
        pool.shutdown();
    }
阅读 3.8k
3 个回答
    @Test
    public void main() throws InterruptedException, FileNotFoundException {
        ExecutorService pool = Executors.newFixedThreadPool(1000);

        ArrayList<Callable<Integer>> arrayList = new ArrayList<>();

        for (int i = 0; i < 1000; i++) {
            int finalI = i;
            arrayList.add(() -> {
                for (int i1 = 0; i1 < 1000; i1++) {
                    FileUtils.writeStringToFile(new File("d.txt"), String.valueOf(finalI), "utf-8", true);
                }
                FileUtils.writeStringToFile(new File("d.txt"), "\n", "utf-8", true);
                return 1;
            });
        }
        pool.invokeAll(arrayList);
        pool.shutdown();
    }
    @Test
    public void main() throws InterruptedException, FileNotFoundException {
        ExecutorService pool = Executors.newFixedThreadPool(1000);

        ArrayList<Callable<Integer>> arrayList = new ArrayList<>();
        FileOutputStream outputStream = new FileOutputStream("/Users/zxd/tmp/2021-07-15/d.txt");

        for (int i = 0; i < 1000; i++) {
            arrayList.add(() -> {
                for (int i1 = 0; i1 < 1000; i1++) {
                    outputStream.write(String.valueOf(i1).getBytes());
                }
                outputStream.write(("\n").getBytes());
                return 1;
            });
        }
        pool.invokeAll(arrayList);
        pool.shutdown();
    }

这两种方法,你都能观察到不安全,使用 FileUtils 写入速度非常慢。

你这种方法能够观察到安全,是因为文件系统每次写入的数据,是有顺序的,如果你两次同时写入一千个字节,这两次的内容是不会截断的(我没有验证过如果两次写入的数据量非常巨大会怎么样),你写入的数据又短又是一致的。

安不安全取决于你怎么去使用,如果你要求我给出的代码中循环写入数据不被截断,那么就必须要使用加锁或者单个线程写入的方法。如果你要求写入速度快,那么就不能使用 FileUtils 频繁关闭打开文件流。

如果你两种需求都没有,速度上没要求,每次写入数据都是整块写入单个线程只写入一次,那么就是线程安全的。

如果是需要多个线程同时写一个文件,要自己做控制,否则不用关心线程安全问题

org.apache.commons.io.FileUtils 是非线程安全的类。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题