Use of AsynchronousFileChannel class

Posted by Erestar on Thu, 11 Jun 2020 07:27:39 +0200

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.

Topics: network Java