上读锁,测试写

场景:Java程序上读锁,其他程序不申请锁直接写
结果:写入失败,但是会清空文件

  1. import java.io.File;
  2. import java.io.FileInputStream;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.nio.ByteBuffer;
  6. import java.nio.channels.FileChannel;
  7. import java.nio.channels.SeekableByteChannel;
  8. import java.nio.file.Files;
  9. import java.nio.file.Path;
  10. import java.nio.file.Paths;
  11. import java.util.Arrays;
  12. public class FileChannelDemo {
  13. public static void writeFile(String filepath) throws IOException {
  14. Path path = Paths.get(filepath);
  15. if (Files.notExists(path)) {
  16. if (Files.notExists(path.getParent())) {
  17. Files.createDirectories(path.getParent());
  18. }
  19. Files.createFile(path);
  20. }
  21. FileOutputStream outputStream = new FileOutputStream(path.toFile());
  22. FileChannel fileChannel = outputStream.getChannel();
  23. ByteBuffer byteBuffer = ByteBuffer.wrap("hello world".getBytes());
  24. fileChannel.write(byteBuffer);
  25. // 重新拿到内容
  26. byteBuffer.rewind();
  27. byteBuffer.position(5);
  28. byte[] bs = " Tom's".getBytes();
  29. byte[] newBs = Arrays.copyOf(bs, bs.length + byteBuffer.remaining());
  30. byteBuffer.get(newBs, bs.length, byteBuffer.remaining());
  31. byteBuffer = ByteBuffer.wrap(newBs);
  32. fileChannel.position(5);
  33. fileChannel.write(byteBuffer);
  34. fileChannel.close();
  35. outputStream.close();
  36. }
  37. }
  1. import java.io.FileInputStream;
  2. import java.io.IOException;
  3. import java.nio.ByteBuffer;
  4. import java.nio.channels.FileChannel;
  5. import java.nio.channels.FileLock;
  6. public class FileLockDemo {
  7. public static final String FILEPATH = "nio-demo/lock.txt";
  8. public static void main(String[] args) throws IOException, InterruptedException {
  9. FileChannelDemo.writeFile(FILEPATH);
  10. FileInputStream inputStream = new FileInputStream(FILEPATH);
  11. FileChannel channel = inputStream.getChannel();
  12. FileLock lock = channel.lock(0, Integer.MAX_VALUE, true);
  13. System.out.println("文件已上锁");
  14. Thread.sleep(10000);
  15. ByteBuffer buffer = ByteBuffer.allocateDirect(32);
  16. channel.read(buffer);
  17. buffer.flip();
  18. byte[] bs = new byte[buffer.remaining()];
  19. buffer.get(bs);
  20. System.out.println("文件读取完成: " + new String(bs));
  21. lock.release();
  22. System.out.println("锁已释放");
  23. channel.close();
  24. inputStream.close();
  25. }
  26. }
  1. import java.io.FileOutputStream;
  2. import java.io.IOException;
  3. public class FileNoLockWriteDemo {
  4. public static void main(String[] args) throws IOException {
  5. System.out.println("准备打开文件");
  6. FileOutputStream outputStream = new FileOutputStream(FileLockDemo.FILEPATH);
  7. byte[] bs = "This is a joke".getBytes();
  8. System.out.println("准备写入");
  9. outputStream.write(bs);
  10. System.out.println("写入完成");
  11. }
  12. }

java异常信息:

  1. 准备打开文件
  2. 准备写入
  3. Exception in thread "main" java.io.IOException: 另一个程序已锁定文件的一部分,进程无法访问。
  4. at java.io.FileOutputStream.writeBytes(Native Method)
  5. at java.io.FileOutputStream.write(FileOutputStream.java:313)
  6. at com.semonx.demoset.io.nio.FileNoLockWriteDemo.main(FileNoLockWriteDemo.java:13)

尝试过使用Notepad++来写文件,结果是一样的:写入失败,文件被清空

上写锁,测试写

场景:Java程序上写锁,其他程序不上锁
结果:在写的过程中,其他进程来写,有可能造成文件数据被破坏

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;

public class FileWriteLockDemo {
    public static final String FILEPATH = "nio-demo/lock.txt";

    public static void main(String[] args) throws IOException, InterruptedException {
        FileChannelDemo.writeFile(FILEPATH);
        FileOutputStream outputStream = new FileOutputStream(FILEPATH);
        FileChannel channel = outputStream.getChannel();

        FileLock lock = channel.lock();
        System.out.println("文件已上锁");
        channel.write(ByteBuffer.wrap("write lock!\r\n".getBytes()));
        Thread.sleep(10000);
        channel.write(ByteBuffer.wrap("write lock!".getBytes()));

        lock.release();
        System.out.println("锁已释放");

        channel.close();
        outputStream.close();
    }
}

推测

文件锁和普通的内存锁应该差不多,只有正确地使用锁,才能保证临界资源的安全性。如果有进程不申请锁就进行访问,是有可能破坏掉文件的。