使用FileLock可以给文件加锁,在多线程和多进程的情况下均有效。(File类的setReadable()等方法只在当前线程中有效。)
代码场景为写进程先获取锁,向文件中写入一串数字后释放锁。读进程等待写进程释放锁后获取锁并输出文件大小。
写进程代码:
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
public class WriteProcess {
public static void main(String[] arg) throws Exception {
RandomAccessFile randomAccessFile = null;
FileChannel channel = null;
try {
randomAccessFile = new RandomAccessFile("test.txt", "rw");
channel = randomAccessFile.getChannel();
FileLock lock = null;
while (null == lock) {
try {
lock = channel.lock();
} catch (Exception e) {
System.out.println("Write Process : get lock failed");
}
}
System.out.println("Write Process : get lock");
for (int i = 0; i < 30; i++) {
randomAccessFile.writeByte(i);
System.out.println("Write Process : write " + i);
Thread.sleep(1000);
}
lock.release();
System.out.println("Write Process : release lock");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != randomAccessFile) {
randomAccessFile.close();
}
if (null != channel) {
channel.close();
}
}
}
}
读进程代码:
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
public class ReadProcess {
public static void main(String[] arg) throws Exception {
RandomAccessFile randomAccessFile = null;
FileChannel channel = null;
try {
Thread.sleep(10000);
randomAccessFile = new RandomAccessFile("test.txt", "rw");
channel = randomAccessFile.getChannel();
FileLock lock = null;
while (true) {
lock = channel.tryLock();
if (null == lock) {
System.out.println("Read Process : get lock failed");
Thread.sleep(1000);
} else {
break;
}
}
System.out.println("Read Process : get lock");
System.out.println("Read Process : get " + randomAccessFile.length() + " numbers");
lock.release();
System.out.println("Read Process : release lock");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != randomAccessFile) {
randomAccessFile.close();
}
if (null != channel) {
channel.close();
}
}
}
}
同时运行读写进程,写进程输出如下:
Write Process : get lock Write Process : write 0 Write Process : write 1 Write Process : write 2 Write Process : write 3 …… Write Process : write 28 Write Process : write 29 Write Process : release lock
读进程输出如下:
……
Read Process : get lock failed Read Process : get lock failed Read Process : get lock failed Read Process : get lock failed Read Process : get lock failed Read Process : get lock Read Process : get 30 numbers Read Process : release lock
这里需要注意:
- 如果同为写进程,可以都使用OutoutStream;
- 如果为一读一写,使用InputStream和OutoutStream无法达到加锁的效果。改为使用RandomAccessFile后,读写进程还必须使用相同的模式(此例中为rw)才可以成功加锁。
- 另外,lock()方法和tryLock()的区别就是lock()是阻塞的,tryLock()是非阻塞的。