`
zachary.guo
  • 浏览: 487263 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

NIO - File Locking

    博客分类:
  • NIO
 
阅读更多
        在 JDK 1.4 版本之前,Java I/O 模型都未能提供文件锁定(file locking),缺少这一特性让人们很头疼。绝大多数现代操作系统早就有了文件锁定功能,而直到 JDK 1.4 版本发布时 Java 编程人员才可以使用文件锁(file lock)。

        锁(lock)可以是共享的(shared)或独占的(exclusive)。这里描述的文件锁定特性在很大程度上依赖本地的操作系统实现。并非所有的操作系统和文件系统都支持共享文件锁。对于那些不支持的,对一个共享锁的请求会被自动提升为对独占锁的请求。这可以保证准确性却可能严重影响性能。

        并非所有平台都以同一个方式来实现基本的文件锁定。在不同的操作系统上,甚至在同一个操作系统的不同文件系统上,文件锁定的语义都会有所差异。一些操作系统仅提供劝告锁定(advisory locking),一些仅提供独占锁(exclusive locks),而有些操作系统可能两种锁都提供。你应该总是按照劝告锁的假定来管理文件锁,因为这是最安全的。但是如能了解底层操作系统如何执行锁定也是非常好的。例如,如果所有的锁都是强制性的(mandatory)而您不及时释放您获得的锁的话,运行在同一操作系统上的其他程序可能会受到影响。

        锁与文件关联,而不是与通道关联。我们使用锁来判优外部进程(决定哪个进程优先访问文件),而不是判优同一个 Java 虚拟机上的线程。如果一个线程在某个文件上获得了一个独占锁,然后第二个线程利用一个单独打开的通道来请求该文件的独占锁,那么第二个线程的请求会被批准。但如果这两个线程运行在不同的 Java 虚拟机上,那么第二个线程会阻塞,因为锁最终是由操作系统或文件系统来判优的并且几乎总是在进程级而非线程级上判优。

        有关 FileChannel 实现的文件锁定模型的一个重要注意项是:锁的对象是文件而不是通道或线程。与文件锁定有关的 FileChannel API 方法:
public abstract class FileChannel extends AbstractChannel implements ByteChannel, GatheringByteChannel, ScatteringByteChannel {

    // This is a partial API listing

    // 等价于 lock(0L, Long.MAX_VALUE, false)
    public final FileLock lock();
    /**
     * An invocation of this method will block until the region can be locked
     *
     * 锁是在文件内部区域上获得的。
     * 
     * 指定文件内部锁定区域开始于 position 并锁定 size 大小的区域。
     * shared 表示你想获取的锁是共享的(参数值为 true)还是独占的(参数值为 false)。
     * 要获得一个共享锁,你必须先以只读权限打开文件,而请求独占锁时则需要写权限。
     * 另外,提供的 position 和 size 参数的值不能是负数。
     *
     * 锁定区域的范围不一定要限制在文件的 size 值以内,锁可以扩展从而超出文件尾。因此,我们可以提前把
     * 待写入数据的区域锁定,我们也可以锁定一个不包含任何文件内容的区域,比如文件最后一个字节以外的区
     * 域。如果之后文件增长到达那块区域,那么您的文件锁就可以保护该区域的文件内容了。相反地,如果你
     * 锁定了文件的某一块区域,然后文件增长超出了那块区域,那么新增加的文件内容将不会受到您的文件锁
     * 的保护。
     */
    public abstract FileLock lock(long position, long size, boolean shared);
    public final FileLock tryLock();
    // lock() 方法的非阻塞变体
    public abstract FileLock tryLock(long position, long size, boolean shared);
}

        Java Doc 上这样描述 FileChannel 的 lock 方法:An invocation of this method will block until the region can be locked. lock 方法会阻塞?和上面描述的貌似不一样?上面描述:如果在同一虚拟机中,另外一个线程调用 lock 会批准,不矛盾吗?其实不然,Java Doc 上描述的内容指的是进程间而不是线程间。再次证明,锁的对象是文件而不是通道或线程。

        在上面的 API 列表中有两个名为 tryLock() 的方法,它们是 lock() 方法的非阻塞变体。这两个 tryLock() 和 lock() 方法起相同的作用,不过如果请求的锁不能立即获取到则会返回一个 null。

        lock() 和 tryLock() 方法均返回一个 FileLock 对象。完整的 FileLock API:
public abstract class FileLock {
    public final FileChannel channel();
    public final long position();
    public final long size();
    public final boolean isShared();
    public final boolean overlaps(long position, long size);
    public abstract boolean isValid();
    public abstract void release() throws IOException;
}

        下面简述部分方法的作用:
  • channel():FileLock 对象由 FileChannel 创建并且总是关联到那个特定的通道实例。可以通过调用 channel() 方法来查询一个 lock 对象以判断它是由哪个通道创建的。
  • isValid():一个 FileLock 对象创建之后即有效,直到它的 release() 方法被调用或它所关联的通道被关闭或 Java 虚拟机关闭时才会失效。我们可以通过调用 isValid() 布尔方法来测试一个锁的有效性。一个锁的有效性可能会随着时间而改变,不过它的其他属性——位置(position)、范围大小(size)和独占性(exclusivity)——在创建时即被确定,不会随着时间而改变。
  • isShared():isShared() 方法用来测试一个锁以判断它是共享的还是独占的。如果底层的操作系统或文件系统不支持共享锁,那么该方法将总是返回 false 值,即使你申请锁时传递的参数值是 true。FileLock 对象是线程安全的,多个线程可以并发访问一个锁对象。
  • overlaps():查询一个 FileLock 对象是否与一个指定的文件区域重叠。这将你您可以迅速判断你拥有的锁是否与一个感兴趣的区域(region of interest)有交叉。不过即使返回值是 false 也不能保证你就一定能在期望的区域上获得一个锁,因为 Java 虚拟机上的其他地方或者外部进程可能已经在该期望区域上有一个或多个锁了。你最好使用 tryLock()方法确认一下。
        尽管一个 FileLock 对象是与某个特定的 FileChannel 实例关联的,它所代表的锁却是与一个底层文件关联的,而不是与通道关联。因此,如果你在使用完一个锁后而不释放它的话,可能会导致冲突或者死锁。在发生错误时,请务必使用 finally 来释放你获得的锁。

        有关独占锁和共享锁,这里总结下:
  1. 独占锁和共享锁都是对文件的部分区域或全部区域进行锁定,然后对这些被锁定的区域做一些操作。
  2. 独占锁被某进程获得后,其它进程若想再获得独占锁,必须等上一个进程释放锁后才能获得。
  3. 文件的某部分区域被一进程获得的独占锁锁定,那么另外一个进程即便是申请同样区域的共享锁,也必须等该块区域的独占锁的进程释放锁才能得到共享锁。
  4. 共享锁被某进程获得后,其它进程是可以再次得到共享锁,并对共享锁锁定的区域进行操作。
  5. 文件的某部分区域被一进程获得的共享锁锁定,那么另外一个进程申请同样区域的独占锁锁,也必须等得到该块区域的共享锁锁的所有进程(这里用的是所有,因为共享锁一旦被某进程获得,其它进程也毫不费吹灰之力也可以得到共享锁)释放锁才能得到独占锁。当然,进程不想等的话,可以得到共享锁。
  6. 上面描述进程得到锁后,用的是可以做一些操作,并没指定要做什么操作。你可以用独占锁来做读操作,用共享锁来做写操作,当然没问题。只要能满足你的需求,你想怎么做都行。
分享到:
评论

相关推荐

    NIO 入门.chm,NIO 入门.chm

    9. **文件锁(File Locking)**:NIO提供了一种锁定文件部分区域的能力,这对于多线程或多进程共享文件时的数据同步非常重要。 NIO的使用虽然相对复杂,但它提供了更高效、灵活的I/O操作方式,尤其适用于处理大量...

    Java NIO详解及源码下载

    4. **文件锁定(File Locking)**:NIO提供了文件锁定功能,可以实现对文件的独占访问,避免多个进程同时修改同一文件的问题。 NIO的应用场景广泛,尤其是在高并发、大数据量的网络应用中,比如服务器端的Socket...

    Java NIO 中文版.rar

    5. **File Locking**:NIO提供了文件锁定机制,可以在文件的特定部分进行独占式访问,避免多线程或进程之间的数据冲突。 6. **Scattering and Gathering**:散列(Scattering)是指从多个Buffer中读取数据到一个...

    Apress.Pro.Java.7.NIO.2.2011

    7. **文件锁(File Locking)**:NIO支持文件锁定,可以避免多个进程或线程同时对同一文件进行读写操作,保证数据的一致性。 8. **字符集转换(Charset)**:NIO提供了更完善的字符集支持,可以方便地进行不同字符...

    NIO.rar

    4. **文件锁(File Locking)**:NIO提供了文件锁功能,允许对文件的特定部分进行锁定,避免在并发环境中出现数据冲突。 5. **字符集(Charsets)**:NIO扩展了字符集的支持,提供了更多的编码和解码选项,使得跨...

    File 线程读写

    3. **文件锁(File Locking)**: - 在Java中,`java.nio.channels.FileLock`接口提供了文件锁的功能,可以实现线程间的互斥访问。在读写文件时,可以使用文件锁来防止多个线程同时写入。 4. **缓冲区(Buffer)与...

    【Java面试资料】-(机构内训资料)上海-拼多多-Java高级

    - 双重检查锁定(Double-Check Locking)与初始化-on-demand holder类设计模式。 5. **IO流与NIO** - 流的分类:字节流与字符流,输入流与输出流,缓冲流与转换流。 - 文件操作:File类的常用方法,文件复制与...

    Java - The Well-Grounded Java Developer

    - **New File System API (NIO.2)**: Detailed explanation of the new file system API, including how it improves upon the older IO model, supports file watching, and provides better file system ...

    JVM基础JVM基础JVM基础

    Java中的锁机制主要有两种:偏向锁(Biased Locking)、轻量级锁(Lightweight Locking)和重量级锁(Heavyweight Locking)。此外,Java还提供了各种同步机制来确保多线程环境下的数据安全性,如synchronized关键字、...

    金蝶BOSV6.1_业务组件API参考手册

    com.kingdee.bos.util.backport.concurrent.locks Interfaces and classes providing a framework for locking and waiting for conditions that is distinct from built-in synchronization and monitors....

Global site tag (gtag.js) - Google Analytics