“This is the 16th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

Pipe

A Java NIO Pipe is a one-way data connection between two threads, and a Pipe has a source channel and a sink channel. Data will be dropped into the Sink channel and read from the source channel.

1. Create a channel

Open the Pipe with the pipe.open () method

Pipe pipe = Pipe.open();
Copy the code

2. Write channel

To write data to the pipe, you need to access the Sink channel.

Pipe.Sinkchannel sinkChannel = pipe.sink();
Copy the code

Write data to Sinkchannel by calling Sinkchannel’s write() method:

String newData = "New String to write to file .." + System.currentTimeMillis();
ByteBuffer buf = ByteBuffer.alloacte(48);

buf.clear();
buf.put(newData.getBytes());
buf.flip();

while(buf.hasRemaining()) {
	sinkChannel.write(buf);
}
Copy the code

3. Read data from the pipe

To read the data from the pipe, access the source channel like this:

Pipe.SourceChannel sourceChannel = pipe.source();
Copy the code

Call the read() method on the source channel to read the data:

ByteBuffer buf = ByteBuffer.allocate(48);
int bytesRead = sourceChannel.read(buf);
Copy the code

The int returned by the read() method tells us how many bytes were read into the buffer.

4, sample

We will read and write data through Pipe, Sink as shown in the following example:

public class PipeDemo {

    public static void main(String[] args) throws IOException {
        // 1 get the pipe
        Pipe pipe = Pipe.open();

        // 2 Get the sink channel
        Pipe.SinkChannel sinkChannel = pipe.sink();

        // 3 Create a buffer
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.put("ha ha!".getBytes(StandardCharsets.UTF_8));
        buffer.flip();

        // 4 Write data
        sinkChannel.write(buffer);

        // 5 source channel
        Pipe.SourceChannel sourceChannel = pipe.source();

        // 6 Create a buffer and read the data
        ByteBuffer buffer2 = ByteBuffer.allocate(1024);
        //buffer2.flip();
        int len = sourceChannel.read(buffer2);
        String str = new String(buffer2.array(), 0, len);
        System.out.println(str);

        // 7 Close the channelsinkChannel.close(); sourceChannel.close(); }}Copy the code

FileLock

FileLock profile

File locking is very common in the OS. If multiple programs access and modify the same file at the same time, it is easy to cause problems when English file data is not synchronized. By adding a lock to a file, only one program can modify the file in the same event, or both programs can only read the file, which solves the synchronization problem.

File locks are process-level, not thread-level. File locks can solve the problem that multiple threads concurrently access and modify the same file, but can not solve the problem that multiple threads concurrently access and modify the same file.

When using a file lock, multiple users in the same process can access and modify the file at the same time.

The file lock is held by the JVM instance of which the current program lock belongs, and once the file lock is acquired (locks the file), it is released either by calling Release () or closing the corresponding FileChannel object, or by exiting the current JVM.

Once a process (such as a JVM instance) locks a file, the process cannot lock the file again until the lock is released, that is, file locks that the JVM instance has placed on the same file cannot overlap (the process level cannot repeatedly acquire locks on the same file).

2. File lock allocation

Exclusive lock: After an exclusive lock is added to a file, the process can read and write the file. The process exclusively reads and writes the file. Other processes cannot read and write the file.

Shared lock: a process locks a file so that other processes can access the file, but these processes can only read the file but cannot write to it. Threads are safe. This file can only be read, not written, as long as another process holds the shared lock. (Actually, you can only share read, not write).

3. Use examples

// Create a FileChannel object. File locks can only be used with a FileChannel object
String pathName = "/xxx/01.txt";
FileChannel fileChannel = new FileOutputStream(pathName).getChannel();

// Lock the file
FileLock lock = fileChannel.lock();

// Read and write to this file
/ /...

/ / releases the lock
lock.release();
Copy the code

The file lock is used through the FileChannel object.

4, get file lock method

There are 4 ways to obtain a file lock:

  • Lock () // Lock the entire file. Default is exclusive lock

  • Lock (Long position, long size, Boolean shared) // Customize lock mode. The first two parameters specify the part to be locked (you can lock only parts of the file), and the third parameter value specifies whether the lock is shared.

  • Trylock () // Lock the entire file. Default is exclusive lock.

  • Trylock (long position, long size, Boolean shared) // Customize lock mode. If the lock is specified as a shared lock, other processes can read the file, but no process can write the file. If a process view writes the file, an exception will be thrown.

5. The difference between lock and trylock

Lock is blocking. If the file lock is not acquired, the current thread will be blocked until the file lock is acquired.

Trylock is the same as lock, except that trylock is non-blocking. Trylock attempts to acquire a file lock and returns the lock object on success. Otherwise, null is returned and the current thread is not blocked.

FileLock two methods

Boolean isShared() // whether this file lock isShared

Boolean isValid() // Whether this file lock is still valid

On some OS, after a file is locked, channel mapping cannot be used for that file.

7. Complete example

public class FileLockDemo2 {


    public static void main(String[] args) throws IOException {
        String input = "hello!";
        System.out.println(input);


        ByteBuffer buffer = ByteBuffer.wrap(input.getBytes(StandardCharsets.UTF_8));
        String pathName = "/xxx/01.txt";
        Path path = Paths.get(pathName);

        FileChannel fileChannel = FileChannel.open(path,
                                                   StandardOpenOption.WRITE, StandardOpenOption.APPEND);
        fileChannel.position(fileChannel.size() - 1);

        / / lock
        FileLock lock = fileChannel.lock();
		// If the lock is shared, subsequent write operations cannot be performed
        //FileLock lock = fileChannel.lock(0, Long.MAX_VALUE, true);
        
        System.out.println("isShared: " + lock.isShared());

        fileChannel.write(buffer);
        fileChannel.close();

        readFile(pathName);
    }

    private static void readFile(String pathName) throws IOException {
        FileReader fileReader = new FileReader(pathName);
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        String str = bufferedReader.readLine();
        System.out.println("Read content:");
        while(str ! =null) {
            System.out.println(""+ str); str = bufferedReader.readLine(); } fileReader.close(); bufferedReader.close(); }}Copy the code