Recently looking at Brian Goetz's <<java concurrent Combat >>, the book has two versions, the electronic industry publishing house is a bad translation, it is recommended to use the mechanical industry press published books.
When I saw the 34th chapter, I suddenly thought of multithreading read-write files, and encountered some problems in the book
1, how to ensure the security of the composite object?
2, how to judge the constraint condition of invariance
3, how do I synchronize with the Synchronized keyword and the lock?
Here is a piece of code that reads data from source and writes it to the target file by multithreading
Ideas:
1, how to Read/write file?
2, how to design reader class?
3, does the reader class need state to describe? How are state variables synchronized?
4, how to ensure that the current thread can accurately read the current segment?
Code Overview:
package org.mushroom.multithread;import java.io.closeable;import java.io.file;import java.io.ioexception;import java.io.randomaccessfile;import java.util.objects;import java.util.concurrent.atomic.atomiclong;/** * points: * 1, divides a file into  , and the size is {@link Reader#segmentLength} {@link Reader#segments} files * , each thread reads pure Block to read the data, the blocks being accessed are tagged with {@link reader#segment} * , and the global variable 1. * 2, multiple threads is final {@ link reader#source}, final {@link reader#target} and * {@link reader#segment}, Need to ensure the security of these variables */public class Reader implements Runnable { Private static final int byte = 1024; private static final long negative_one = -1l; private static final long zero = 0l; private static final long one = 1l; // Global variables for multithreaded access block private final atomiclong segment = new atomiclong (negative_one); // Single File size private final int segmentlength = 30 * byte * byte; // Original File private final File source; // file private final file target; /after copying The number of blocks after the/ file is divided private final long segments; // Last piece of file actual size private final long remains; Public reader (String sourcepath, string targetpath) throws ioexception { &nbsP; this.source = new file (SourcePath); this.target = new file (TargetPath); if (!this.target.exists ()) { This.target.createNewFile (); } this.remains = (This.source.length () % segmentlength); //If the remainder is not 0, then one more block is needed to store the extra bytes, otherwise it will be lost if (This.remains != zero) { this.segments = this.source.length () / segmentLength + one; } else { this.segments = sourcepath.length () / segmentLength; } } /** * run: * 1, while true: the current block is not accessed, from {@link reader# SEGMENT&NBSP;=&NBSP;0} started the first visit to * 2, {@link reader#readblock ( Randomaccessfile, long)} reads data from the file and returns byte[] * 3, {@link Reader#writeblock (Randomaccessfile, byte[], long)}, the buffer is written to the file after setting the position * / public void run () { Randomaccessfile reader = null; randomaccessfile writer = null; try { &nBsp; reader = new randomaccessfile (source, "R"); writer = new randomaccessfile (target, "RW" ); long position = -1l; //Loop count Current segment, multiple threads can be modified while (position = Segment.incrementandget ()) < segments) { final byte[] bytes = readblock (Reader, position); writeblock (writer, bytes, position); } } catch (ioexception e) { e.printstacktrace (); } finally { close (writer); close (reader); } } private void writeblock ( Randomaccessfile writer, byte[] bytes, long position) throws IOException { writer.seek (position * segmentlength); writer.write (bytes); } /** * 1, reader set POSITION&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;*&NBSP;2, Creating a buffered array * 3, writes data to byte[] * 4, returns buffer array * * @return position for {@link randomaccessfile# Write (byte[])} using */ private byte[] readblock ( Randomaccessfile reader, long position) throws IOException { reader.seek (position * segmentlength); final byte[] bytes = new byte[getwritelength (position)]; reader.read (bytes); return bytes; } /** * Get current byte[] The actual writable length may be {@link Reader#segmentLength} or {@link Reader#remains} */ &Nbsp; private int getwritelength (long position) throws IOException { if (Position == segments + negative_one && remains > zero) { return (int) remains; } return segmentLength; } /** * Common interface method for closing a stream * * @param closeable */ private void close (closeable closeable) { try { if (Objects.nonnull ( closeable)) { closeable.close (); } } catch (ioexception e) { E.printstacktrace (); } }}
Test code: Note that JUnit is powerless with multithreaded testing, it is recommended to use groboutils or simply the Main method
package org.mushroom.multithread;import java.io.IOException;public class ReaderTest { public static void main (String[] args) throws ioexception { final String source = ""; final String target = ""; reader reader = new reader (Source, target); new thread (reader). Start (); new thread (reader). Start (); new thread (reader). Start (); new thread (reader). Start (); }}
How to resolve:
1, multi-threaded read files need to read data from different places, so the normal stream does not meet the requirements, so choose Java.io.RandomAccessFile It can be arbitrarily set file cursor. and contains Read&write way
2,①reader&writer Design
Multithreaded execution is the reader class of the Run method, so each thread must have its own independent reader&writer, so reader&writer must be thread-private, that is, the need to reader& In the writer wrapper thread, the reader&writer between threads cannot be shared.
② how to deal with Source&target?
each thread handles its own block of responsibility, and the final block is a complete target. That is, the source is divided into segment blocks of size segment length, but note that the actual valid data length of the last segment block is not segment length.
③ Other domain design
Requires two file to describe source⌖
Two variables are required to describe how many segments the source is divided into and the size of the segment segmentlength;
A variable is required to describe the size of the last piece of remain;
A shared variable segment is required to describe the file status of the source file;
3, the source file needs a segment variable to describe its status as multithreaded, that is, where the current thread is being processed. And those that haven't been processed yet.
4,thread read segment can use a java.util.concurrent.atomic. A variable of type Atomiclong describes it (that is, the main description of the current block is the number of blocks), the Atomiclong class of the increment/decrement operation is thread-safe. So the location of each block read is safe.
This article is from the "Small mushroom blog Big World" blog, please be sure to keep this source http://smallmushroom.blog.51cto.com/9474297/1862018
Java Concurrent Read & write files