JAVA文件锁

         最近项目里碰到了个问题,在Linux环境上,Thread1通过java.nio.channels.FileLock给文件加锁,通过Thread2竟然能删除这个文件,突然感觉很奇怪,Windows环境上不是这样的行为啊,因此就顺便研究了下java文件锁的机制。
       首先看一下如何简单实现一个java的文件锁


package com.pracbiz.b2bportal.core.eai.backend;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;

public class TestLock
{
	public static void main(String[] args) throws IOException, InterruptedException
	{
        RandomAccessFile input = null;
        FileChannel channel = null;
        FileLock lock = null;
        final File source = new File("/Users/youwenwu/Downloads/a.txt");
        try
        {
            if (source.exists())
            {
                input = new RandomAccessFile(source, "rw");
                //step 1.获取FileChannel,获取channel有3种方式,分别是调用
                //FileInputStream,FileOutputStream以及RandomAccessFile
                //实例的getChannel方法.
                channel = input.getChannel();
                //step 2.获取FileLock
                lock = channel.tryLock();
            }
        }
        finally
        {
        	if (lock != null)
        	{
        		lock.release();
        		lock = null;
        	}
        	
        	if (channel != null)
        	{
        		channel.close();
        		channel = null;
        	}
        	
        	if (input != null)
        	{
        		input.close();
        		input = null;
        	}
        }
	}
}


         FileLock是通过调用FileChannel的lock或tryLock方法来获取的,lock获取不到当前线程会处于阻塞等待状态,tryLock不管是否成功获得锁都会立即返回。
       FileLock分两种,共享锁(shared)和排它锁(exclusive),多个线程可以同时持有同一个文件的共享锁,但但如果有一个线程持有了一个文件的排它锁,则其它线程将无法获取该文件的锁(包括共享锁和排它锁),这里有一点要特别留意,并不是所有的操作系统都支持共享锁,如果某个操作系统不支持共享锁,那么FileChannel的lock或tryLock会自动返回排它锁,如何判断一个FileLock为共享锁还是排它锁,只需要调用lock.isShared方法即可,返回true则为共享锁,false为排它锁。
        那接下来回到我们之前的问题,为什么Linux环境下,Thread1持有File1的lock,但是Thread2却能删除File1,我们知道,对于结构型数据库,如果一个存储过程对某一张表中的某一条记录加锁,那另一个存储过程是无法删除该条记录的,这是因为删除一条记录需要获取该记录的独占锁,但是一条记录的独占锁同一时刻只能由一个存储过程获取,所以很显然,这里是删除失败(关于数据库的锁目前就点到为止,不是我们这篇文章需要讨论的范围),那么这里很容易让我们想到,难道Thread2在删除File1的时候不需要获取该文件的锁?这样不是非常不安全吗?带着这个疑问,我查了java api发现,原来锁在操作系统级别有两个特征,协同(advisory)和强制(mandatory),这个是平台相关的,windows平台的锁是mandatory的,linux平台的锁则是advisory的,关于这两种特征的行为,大致可以总结为以下两点,advisory特征的锁并不会阻止其它线程对该文件的访问甚至删除,但mandatory特征的锁会完全阻止其它线程对文件的任何违反锁规则的访问(比如read并不会违反锁规则,但update或者delete却是违反了锁规则),而且java api也明确的告诉我们不要希望lock来帮你阻止其它程序对文件的访问。
        该贴持续更新,会加入更多实验数据




猜你喜欢

转载自995215629-qq-com.iteye.com/blog/2211914