/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.nio.channels; import java.io.IOException; /** * A {@code FileLock} represents a locked region of a file. * <p> * Locks have certain properties that enable collaborating processes to avoid * the lost update problem or reading inconsistent data. Logically, a file lock * can be <em>exclusive</em> or <em>shared</em>. Multiple processes can hold * shared locks on the same region of a file, but only a single process can hold * an exclusive lock on a given region of a file and no other process can * simultaneously hold a shared lock overlapping the exclusive lock. An * application can determine whether a {@code FileLock} is shared or exclusive * via the {@code isShared()} method. * <p> * Locks held by a particular process cannot overlap one another. Applications * can determine whether a proposed lock will overlap by using the {@code * overlaps(long, long)}) method. Locks held in other processes may overlap * locks held in this process. Locks are shared amongst all threads in the * acquiring process, and are therefore unsuitable for intra-process * synchronization. * <p> * Once a lock is acquired, it is immutable in all its state except {@code * isValid()}. The lock will initially be valid, but may be rendered invalid by * explicit removal of the lock, using {@code release()}, or implicitly by * closing the channel or exiting the process (terminating the VM). * <h3>Platform dependencies</h3> * <p> * Locks are intended to be true platform operating system file locks, and * therefore locks held by the VM will be visible to other * operating system processes. * <p> * The characteristics of the underlying operating system locks will show * through in the Java implementation. For example, some platforms' locks are * 'mandatory' -- meaning the operating system enforces the locks on processes * that attempt to access locked regions of files; whereas other platforms' * locks are only 'advisory' -- meaning that processes are required to * collaborate to ensure locks are acquired and there is a potential for * processes to not play well. To be on the safe side, it is best to assume that * the platform is adopting advisory locks and always acquire shared locks when * reading a region of a file. * <p> * On some platforms, the presence of a lock will prevent the file from being * memory-mapped. On some platforms, closing a channel on a given file handle * will release all the locks held on that file -- even if there are other * channels open on the same file; their locks will also be released. The safe * option here is to ensure that you only acquire locks on a single channel for * a particular file and that becomes the synchronization point. * <p> * Further care should be exercised when locking files maintained on network * file systems, since they often have further limitations. */ public abstract class FileLock implements AutoCloseable { // The underlying file channel. private final FileChannel channel; // The lock starting position. private final long position; // The lock length in bytes private final long size; // If true then shared, if false then exclusive private final boolean shared; /** * Constructs a new file lock instance for a given channel. The constructor * enforces the starting position, length and sharing mode of the lock. * * @param channel * the underlying file channel that holds the lock. * @param position * the starting point for the lock. * @param size * the length of the lock in number of bytes. * @param shared * the lock's sharing mode of lock; {@code true} is shared, * {@code false} is exclusive. */ protected FileLock(FileChannel channel, long position, long size, boolean shared) { if (position < 0 || size < 0 || position + size < 0) { throw new IllegalArgumentException("position=" + position + " size=" + size); } this.channel = channel; this.position = position; this.size = size; this.shared = shared; } /** * Returns the lock's {@link FileChannel}. */ public final FileChannel channel() { return channel; } /** * Returns the lock's starting position in the file. * * @return the lock position. */ public final long position() { return position; } /** * Returns the length of the file lock in bytes. * * @return the size of the file lock in bytes. */ public final long size() { return size; } /** * Indicates if the file lock is shared with other processes or if it is * exclusive. * * @return {@code true} if the lock is a shared lock, {@code false} if it is * exclusive. */ public final boolean isShared() { return shared; } /** * Indicates if the receiver's lock region overlaps the region described * in the parameter list. * * @param start * the starting position for the comparative lock. * @param length * the length of the comparative lock. * @return {@code true} if there is an overlap, {@code false} otherwise. */ public final boolean overlaps(long start, long length) { final long end = position + size - 1; final long newEnd = start + length - 1; if (end < start || position > newEnd) { return false; } return true; } /** * Indicates whether this lock is a valid file lock. The lock is * valid unless the underlying channel has been closed or it has been * explicitly released. * * @return {@code true} if the lock is valid, {@code false} otherwise. */ public abstract boolean isValid(); /** * Releases this particular lock on the file. If the lock is invalid then * this method has no effect. Once released, the lock becomes invalid. * * @throws ClosedChannelException * if the channel is already closed when an attempt to release * the lock is made. * @throws IOException * if another I/O error occurs. */ public abstract void release() throws IOException; /** * Calls {@link #release} for {@code AutoCloseable}. * * @since 1.7 */ public final void close() throws IOException { release(); } /** * Returns a string that shows the details of the lock suitable for debugging. */ @Override public final String toString() { return "FileLock[position=" + position + ", size=" + size + ", shared=" + shared + "]"; } }