Use of AsynchronousFileChannel class
The asynchronusfilechannel class is used to read, write, and manipulate asynchronous channels of files.
When you open a file by calling the open() method defined by this class, an asynchronous file channel is created. The file contains a read-write variable length sequence of bytes that can be queried for its current size. When a writer byte exceeds its current size, the size of the file increases. The size of the file is reduced when it is truncated.
The asynchronous file channel does not have the current location in the file, but rather assigns the file location to each read and write method that initiates the asynchronous operation.
CompletionHandler is specified as a parameter and called to consume the results of the I/O operation. This class also defines the read and write methods to start an asynchronous operation and returns a Future object to represent the pending result of the operation. In the Future, it can be used to check whether the operation has completed, wait for completion, and then retrieve the results.
In addition to read and write operations, this class also defines the following operations:
1. Updates to files may be forced to underlying storage devices to ensure that data is not lost in the event of a system crash
2. An area of the file may be locked by access of other programs
Asynchronusfilechannel is associated with a thread pool, and tasks are submitted to process I/O events and sent to the CompletionHandler object that uses the results of I/O operations on the channel. The CompletionHandler for I/O operations initiated on the channel is guaranteed to be called by a thread in the thread pool (this ensures that the CompletionHandler program is run by a thread with the expected identity). If the I/O operation completes immediately and the starting thread itself is a thread in the thread pool, the starting thread can directly call the completion handler. When you create an asynchronous filechannel without specifying a thread pool, the channel is associated with the system related default thread pool, which may be shared with other channels. The default thread pool is configured by the system properties defined by the AsynchronousChannelGroup class.
This type of channel can be safely used by multiple concurrent threads. The close() method can be called at any time, as specified by the channel interface. This causes all outstanding asynchronous operations on the channel to use the exception AsynchronousCloseException. Multiple read and write operations may be incomplete at the same time. When multiple read and write operations are not completed, the order of the I/O operations and the order in which the CompletionHandler program is called are not specified. In particular, they did not guarantee that they would be carried out in the order in which the actions were initiated. The ByteBuffers used to read or write to people are not secure and cannot be used by multiple concurrent I/O operations. In addition, after you start an I/O operation, you should be careful to ensure that the buffer is not accessible until the operation is complete.
As with FileChannel, the view of files provided by instances of this class is consistent with other views of the same file provided by other instances of the same program. However, the views provided by the instances of this class may be the same as those seen by other concurrent running programs, or they may not be the same. This is due to the delay caused by the cache and network file system protocol executed by the underlying operating system. This is true regardless of the language in which these programs are written, whether they run on the same machine or on other machines. The exact nature of any such inconsistency depends on the system and is therefore not specified.
Get exclusive lock for this channel file
The public final future < FileLock > lock() method is used to obtain the exclusive lock of this channel file. This method initiates an operation to obtain an exclusive lock on the file for this channel. This method returns a future object that represents the pending result of the operation. Future's get() method returns FileLock on successful completion. The behavior of calling this method and the way and code of calling ch.lock(OL,Long.MAX__VALUE,false). The return value represents the future. Object of the pending result.
//Test A public static void main(String[] args) throws ExecutionException, InterruptedException, IOException { Path path = Paths.get("a.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); Future<FileLock> future = channel.lock(); FileLock lock = future.get(); System.out.println("A get lock time=" + System.currentTimeMillis()); //Give some events to start another class Thread.sleep(8000); lock.release(); System.out.println("A release lock time=" + System.currentTimeMillis()); channel.close(); } //Test class B public static void main(String[] args) throws ExecutionException, InterruptedException, IOException { Path path = Paths.get("a.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); System.out.println("lock begin " + System.currentTimeMillis()); Future<FileLock> future = channel.lock(); System.out.println("lock end " + System.currentTimeMillis()); FileLock lock = future.get(); System.out.println("B get lock time=" + System.currentTimeMillis()); lock.release(); channel.close(); channel.close(); }
Run A before B:
A get lock time=1591806128921 A release lock time=1591806136923 //A output //B output lock begin 1591806130471 lock end 1591806130475 B get lock time=1591806136924//A releases the lock before B obtains it
Get the lock of the given area of the channel file
The function of public abstract future < firelock > lock (long position, long size, Boolean shared method is to obtain the lock of the given area of this channel file. This method starts an operation to get the
Lock.
The behavior of this method is exactly the same as that of the lock(long,long, boolean, Object, Completion handler) method
In the same way, this method does not specify the Completion Handler program, but returns a Future representing the pending result
Object.
The get0 method of Future returns Firelock upon successful completion. The parameter position represents the starting position of the lock area, which must be a non negative number. Size represents the size of the locked area, which must be non negative, and the result of position+size must be non negative. The value of shared is tue, which means the requested shared lock. In this case, the channel must be opened for reading (and possibly writing). If an exclusive lock is requested, in this case, the channel must be opened for writing (and possibly reading). The return value represents the Future object of the pending result.
//TestA public static void main(String[] args) throws IOException, ExecutionException, InterruptedException { Path path = Paths.get("a.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); Future<FileLock> future = channel.lock(0, 3, false); FileLock lock = future.get(); System.out.println("A get lock time=" + System.currentTimeMillis()); Thread.sleep(8000);//Give the event to start TestB lock.release(); System.out.println("A release lock time=" + System.currentTimeMillis()); channel.close(); }
//TestB public static void main(String[] args) throws Exception{ Path path = Paths.get("a.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); System.out.println("B lock begin=" + System.currentTimeMillis()); Future<FileLock> future = channel.lock(0, 3, false); System.out.println("B lock end=" + System.currentTimeMillis()); FileLock lock = future.get(); System.out.println("B get lock time=" + System.currentTimeMillis()); lock.release(); channel.close(); }
//TestC public static void main(String[] args) throws Exception{ Path path = Paths.get("a.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); System.out.println("c lock begin " + System.currentTimeMillis()); Future<FileLock> future = channel.lock(4, 4, false); System.out.println("c lock end " + System.currentTimeMillis()); FileLock lock = future.get(); System.out.println("c get lock time=" + System.currentTimeMillis()); lock.release(); channel.close(); }
Run A before B:
//A A get lock time=1591844912927 A release lock time=1591844920930 //B B lock begin=1591844915954 B lock end=1591844915957 B get lock time=1591844920930//A release B to get
Run A before C:
//A A get lock time=1591844962242 A release lock time=1591844970245 //C c lock begin 1591844964512 c lock end 1591844964515 c get lock time=1591844964517//A and C lock in different areas and are not blocked
Achieve overlap lock
Blocking occurs when two processes have overlapping locking ranges for the same file.
//A public static void main(String[] args) throws Exception{ Path path = Paths.get("a.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); Future<FileLock> future = channel.lock(0, 3, false); FileLock lock = future.get(); System.out.println("A get lock time=" + System.currentTimeMillis()); Thread.sleep(8000); lock.release(); System.out.println("A release lock time=" + System.currentTimeMillis()); channel.close(); }
//B public static void main(String[] args) throws Exception{ Path path = Paths.get("a.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); System.out.println("lock begin " + System.currentTimeMillis()); Future<FileLock> future = channel.lock(1, 5, false); System.out.println("lock end " + System.currentTimeMillis()); FileLock lock = future.get(); System.out.println("B get lock time=" + System.currentTimeMillis()); lock.release(); channel.close(); }
//A A get lock time=1591845350042 A release lock time=1591845358046 //B lock begin 1591845351759 lock end 1591845351761 B get lock time=1591845358046
Returns the current size of this channel file and the channel open status
The public abstract long size() method returns the current size of this channel file.
The public Boolean is open() method is used to determine whether the channel is open.
public static void main(String[] args) throws Exception{ Path path = Paths.get("a.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); System.out.println("File size=" + channel.size()); System.out.println("A isOpen=" + channel.isOpen()); channel.close(); System.out.println("B isOpen=" + channel.isOpen()); }
File size=100 A isOpen=true B isOpen=false
Use of CompletionHandler interface
The public final < a > void lock (attachment, completionhandler < filelock,? Super a > handler) method is used to obtain the exclusive lock of this channel file. This method initiates an operation to obtain a lock for a given area of this channel file.
The handler parameter is the CompletionHandler object that is called when the lock is acquired (or the operation fails). The result passed to the CompletionHandler is the generated FileLock.
Call this method ch.lock(att, handler) behavior and mode ch.lock(0L, Long.MAX_ VALUE, false,att, handler). Parameter A represents the data type of the attachment. The parameter attachment represents the object to attach to the I0 operation, which can be empty. CompletionHandler represents the handler that consumes the result.
public static void main(String[] args) throws Exception{ Path path = Paths.get("a.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); System.out.println("begin time=" + System.currentTimeMillis()); channel.lock("I'm value added", new CompletionHandler<FileLock, String>() { @Override public void completed(FileLock result, String attachment) { try { System.out.println("public void completed(FileLock result, String attachment attachment=)" + attachment); result.release(); channel.close(); System.out.println("release end close"); } catch (IOException e) { e.printStackTrace(); } } @Override public void failed(Throwable exc, String attachment) { System.out.println("public void failed(Throwable exc, String attachment) attachment=" + attachment); System.out.println("getMessage=" + exc.getMessage()); } }); System.out.println("end time=" + System.currentTimeMillis()); Thread.sleep(3000); }
begin time=1591846382781 end time=1591846382784 public void completed(FileLock result, String attachment attachment=)I am value added release end close
It can be found that the time of begin and end are very close, almost the same time, which is the advantage of asynchronous.
public void failed(Throwable exc, A attachment) method call time
The public void failed(Throwable exc, A attachment) method is called when an I/O operation exception occurs.
public static void main(String[] args) throws Exception{ Path path = Paths.get("a.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.READ); channel.close(); channel.lock("I'm a string I'm an attachment", new CompletionHandler<FileLock, String>() { @Override public void completed(FileLock result, String attachment) { try { result.release(); } catch (IOException e) { e.printStackTrace(); } } @Override public void failed(Throwable exc, String attachment) { System.out.println("public void failed(Throwable exc, String attachment) attachment"); System.out.println("attachment=" + attachment + " exc.getMessage()=" + exc.getMessage()); System.out.println("exc.getClass().getName()=" + exc.getClass().getName()); } }); Thread.sleep(3000); }
public void failed(Throwable exc, String attachment) attachment attachment=I'm a string I'm an attachment exc.getMessage()=null exc.getClass().getName()=java.nio.channels.ClosedChannelException
Perform the specified range of locking and incoming attachments and integration interfaces
The function of public abstract < a > void lock (long position, long size, Boolean shared, a attachment, completionhandler < filelock,? Super a > handler) method is to integrate the public abstract future < filelock > lock (long position, long size, Boolean shared) method and public final < a > void lock (a attachment, completionhandler < filelock,? Super a > handler).
public static void main(String[] args) throws Exception{ Path path = Paths.get("a.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); System.out.println("begin time=" + System.currentTimeMillis()); channel.lock(0, 3, false, "I am value added", new CompletionHandler<FileLock, String>() { @Override public void completed(FileLock result, String attachment) { try { System.out.println("public void completed(FIleLock result, String attachment) attachment=" + attachment); result.release(); } catch (IOException e) { e.printStackTrace(); } } @Override public void failed(Throwable exc, String attachment) { System.out.println("public void failed(Throwable exc, String attachment) attachment=" + attachment); System.out.println("getMessage=" + exc.getMessage()); } }); System.out.println("end time=" + System.currentTimeMillis()); Thread.sleep(3000); channel.close(); }
begin time=1591847712982 end time=1591847712985 public void completed(FIleLock result, String attachment) attachment=I am value added
Execute locking and incoming attachment and integration interface CompletionHandler
If the public final < a > void lock (a attachment, completionhandler < filelock,? Super a > handler) method fails to obtain the lock, wait.
//A public static void main(String[] args) throws Exception{ Path path = Paths.get("a.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); System.out.println("A begin time=" + System.currentTimeMillis()); channel.lock("I am value added A", new CompletionHandler<FileLock, String>() { @Override public void completed(FileLock result, String attachment) { try { Thread.sleep(9000); result.release(); System.out.println("A release lock time=" + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } @Override public void failed(Throwable exc, String attachment) { System.out.println("public void failed(Throwable exc, String attachment) attachment=" + attachment); System.out.println("getMessage=" + exc.getMessage()); } }); System.out.println("A end time=" + System.currentTimeMillis()); Thread.sleep(10000); channel.close(); }
//B public static void main(String[] args) throws Exception{ Path path = Paths.get("a.txt"); AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE); System.out.println("B begin time=" + System.currentTimeMillis()); channel.lock("I am value added B", new CompletionHandler<FileLock, String>() { @Override public void completed(FileLock result, String attachment) { try { System.out.println("public void completed(FileLock result, String attachment) attachment" + attachment); result.release(); System.out.println("B get lock time=" + System.currentTimeMillis()); result.release(); channel.close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void failed(Throwable exc, String attachment) { System.out.println("public void failed(Throwable exc, String attachment) attachment=" + attachment); System.out.println("getMessage=" + exc.getMessage()); } }); System.out.println("B end time=" + System.currentTimeMillis()); Thread.sleep(50000); }
//A A begin time=1591848196884 A end time=1591848196886 A release lock time=1591848205892 //B B begin time=1591848198806 B end time=1591848198811 public void completed(FileLock result, String attachment) attachment I am value added B B get lock time=1591848205893
1591848205893 minus 1591848196884 is equal to 9009, indicating that A locks for 9s before B obtains the lock.