import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.archermind.nwa.networkagent.log.Logger;
public class TestServlet extends HttpServlet {
private static Logger logger = Logger
.getLogger(TestServlet.class.getName());
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
File f = new File("F://kankan//opt.txt");
RandomAccessFile fi = new RandomAccessFile(f, "rw");
FileChannel fc = fi.getChannel();
FileLock fl = null;
Thread t = Thread.currentThread();
logger.info(t.getId() + " " + t.getName());
InetAddress address = InetAddress.getLocalHost();
try {
try {
fl = fc.tryLock();
if (fl == null) {
logger.info(address.getHostAddress() + " wait 5 sec for reason (null)!");
throw new OverlappingFileLockException();
}
} catch (OverlappingFileLockException e) {
logger.info(address.getHostAddress() + " wait 5 sec once!");
try {
Thread.sleep(5 * 1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
fl = fc.tryLock();
if (fl == null) {
logger.info(address.getHostAddress() + " wait 5 sec for reason (null)!");
throw new OverlappingFileLockException();
}
} catch (OverlappingFileLockException oe) {
logger.info(address.getHostAddress()
+ " cannot get file lock!");
throw new OverlappingFileLockException();
}
}
if (fl != null) {
logger.info(address.getHostAddress() + " start write!");
fc.position(fc.size());
fc
.write(ByteBuffer
.wrap((address.getHostAddress() + " =============1=============== /r/n")
.getBytes()));
logger.info(address.getHostAddress() + " stop write!");
}
} catch (Exception e) {
logger.info(address.getHostAddress()
+ " exception or cannot get file lock!");
response.getWriter().write(address.getHostAddress()
+ " exception or cannot get file lock!");
return;
} finally {
if (null != fl && fl.isValid()) {
fl.release();
logger.info(address.getHostAddress() + " release filelock");
}
fc.close();
fi.close();
}
}
}
文件加锁是 JDK1.4 引入的一种机制,它允许我们同步访问某个作为共享资源的文件。竞争同一文件的两个线程可能在不同的 Java 虚拟机上,或者一个是 Java 线程,另一个是操作系统中的某个本地线程。文件锁对其他的操作系统进程是可见的,因为 Java 的文件加锁直接映射到了本地操作系统的加锁工具。
通过对 FileChannel 调用 tryLock() 或 lock() ,就可以获得整个文件的 FileLock 。特殊的是, SocketChannel/DatagramChannel/ServerSocketChannel 不需要加锁,因为它们是从单进程实体继承而来,我们通常不在两个进程之间共享网络的 socket 。
Trylock 与 lock 方法
tryLock() 是非阻塞式的,它设法获取锁,但如果不能获得,例如因为其他一些进程已经持有相同的锁,而且不共享时,它将直接从方法调用返回。
lock() 是阻塞式的,它要阻塞进程直到锁可以获得,或调用 lock() 的线程中断,或调用 lock() 的通道关闭。
对独占锁和共享锁的支持必须由底层的操作系统提供。锁的类型可以通过 FileLock.isShared() 进行查询。另外,我们不能获取缓冲器上的锁,只能是通道上的。
OverlappingFileLockException 与 锁的作用域
在某个文件加锁 锁只会作用在此文件上 对其他文件无效
单个 Java 虚拟机在某个特定文件上所保持的锁定是不重叠的,即同一个 jvm 中不同线程去拿同一文件的锁时,先拿到的获得锁,后获取的无法获得锁, tryLock ()方法不会抛出异常,但获得锁值为 null 。
不同 jvm 或者不同操作系统获取同一文件锁时,先拿到的获得锁,后获取的抛出文件重叠锁异常【 OverlappingFileLockException 】。以上是 windows 才会出现如此现象,如果是 linux 会抛出异常:【 java.io.IOException: Permission denied 】
共享锁 与 独占锁 区别
独占锁 :也称排它锁,如果一个线程获得一个文件的独占锁,那么其它线程就不能再获得同一文件的独占锁或共享锁,直到独占锁被释放。
共享锁 :如果一个线程获得一个文件的共享锁,那么其它线程可以获得同一文件的共享锁或同一文件部分内容的共享锁,但不能获取排它锁
当 a.txt 文件被加独占锁时 其他线程不可读也不可写
当 a.txt 文件被加共享锁时 其他线程可读也不可写
如何获得共享锁
fc.tryLock(position,size,isShare); 第三个参数为 true 时 为共享锁
以下为 api (注意共享锁需要操作支持,如果操作系统不支持共享锁,则自动变更为独占锁)