Java Multithread Breakpoint Continuous Code Explanation

Keywords: Java network

Several key steps of multi-threaded breakpoint continuous download:

1. Create temporary file space and calculate the size of each thread that needs to be downloaded

2. startIndex and endIndexe are required for each thread to download. Using the length of the obtained stream divided by size, the size of each thread is obtained, but if the endless amount is left to the last thread to download.

3. Guarantee the mechanism of breakpoint continuation, using temporary files to store the download progress of each thread. Before each download begins, judge whether the temporary file exists and the corresponding thread download record. Start the download according to the record, judge whether each thread has finished downloading, and delete the temporary files through a loop if all the downloads are completed, in order to avoid and Delete temporary files should be locked in the send operation.

4. Specific download process, get the connection again, get the read stream according to the status code of 206, and then Java In the process of io reading and writing, Random Access File is needed to create and write temporary files. Simply speaking, because the parts requested by each thread are different, the time of writing is not written from scratch. Random Access File's seek method supports the location of writing time, that is, the location of writing time. Write the file in the specified location, and then put together several parts to complete the file to download.

5. In addition, there are some details that need to be noticed, such as requesting the code of the network to be implemented in the sub-thread, that is, the code of the specific download process part.

The following is the specific implementation code, which contains detailed annotations:

package com.nocol.mutildownload;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * @author lxp
 *
 * @TODO
 * 
 */

public class MutilDownLoad {
	
	//Get the file download path
	public static String path = "http://192.168.56.1:8080/haozip.exe";
	// Define the number of threads
	public static int ThreadCount = 3;

	// === Define running threads===
	public static int RunningThread;

	public static void main(String[] args) throws Exception {
		// Connect to the server to get the length of the downloaded file
		// Create URL objects
		URL url = new URL(path);
		// Get the connection object
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		// Setting the way to request data
		conn.setRequestMethod("GET");
		// Set request timeout
		conn.setReadTimeout(5000);
		// Get the server status code
		int code = conn.getResponseCode();
		if (code == 200) {
			// Get the actual length of the file
			int lenth = conn.getContentLength();

			// === Assign the number of threads to the running thread====
			RunningThread = ThreadCount;

			// Create a file space to download files
			RandomAccessFile raf = new RandomAccessFile(getName(path), "rw");
			// Specify the length of the space (the same length as the file to download)
			raf.setLength(lenth);
			raf.close();
			// Set the file length for each thread to download
			int blockSize = lenth / ThreadCount;
			for (int ThreadId = 1; ThreadId <= ThreadCount; ThreadId++) {
				// Set the start location of downloads without each thread
				int startIndex = (ThreadId - 1) * blockSize;
				int endIndex = startIndex + (blockSize - 1);
				if (ThreadId == ThreadCount) {
					endIndex = lenth;
				}

				System.out.println(ThreadId + "Size of theoretical download:" + startIndex + "-----" + endIndex);

				// Open Thread Download
				DownLoadThread downLoadThread=new DownLoadThread(startIndex, endIndex, ThreadId);
				downLoadThread.start();
			}
		}
	}

	// Create Thread Download Files
	public static class DownLoadThread extends Thread {//Static inner class

		private int startIndex;
		private int endIndex;
		private int ThreadId;

		public DownLoadThread(int startIndex, int endIndex, int ThreadId) {
			this.endIndex = endIndex;
			this.startIndex = startIndex;
			this.ThreadId = ThreadId;
		}

		@Override
		public void run() {
			try {
				// Create URL objects
				URL url = new URL(path);
				// Get the connection object
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				// Setting the way to request data
				conn.setRequestMethod("GET");
				// Set request timeout
				conn.setReadTimeout(5000);

				// == Encapsulate files that record thread locations into File objects
				File file = new File(ThreadId + ".txt");
				// == Determine whether there is a file that saves the download location of the thread before downloading to determine whether to continue to upload breakpoints
				if (file.exists()) {
					FileInputStream fis = new FileInputStream(file);
					BufferedReader br = new BufferedReader(new InputStreamReader(fis));
					// Get the last location of the thread Download
					String Lastpostion = br.readLine();
					// Change to int type
					int LastPositionn = Integer.parseInt(Lastpostion);
					// Assign the position to the starting position
					startIndex = LastPositionn;
					// Release resources
					fis.close();

					System.out.println(ThreadId + "The actual download size:" + startIndex + "-----" + endIndex);
				}

				// Important: Request server download part of the file specified location (request header information)
				conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
				// Get the server status code
				int code = conn.getResponseCode();
				if (code == 206) {// The status code = 206 indicates the success of the request for part of the resource
					// Get the input stream object
					InputStream in = conn.getInputStream();
					// Creating Random Access File Objects
					RandomAccessFile raf = new RandomAccessFile(MutilDownLoad.getName(path), "rw");
					// Specify the start location of the thread download file
					raf.seek(startIndex);

					// Write the read file to the created file space
					int len = 0;
					byte[] bys = new byte[1024 * 1024];

					// === Define the size of the current thread Download
					int total = 0;

					while ((len = in.read(bys)) != -1) {
						raf.write(bys, 0, len);

						// == Tot is the size of the file that each thread downloads from its actual location.
						total += len;
						// == To achieve breakpoint continuation, get the location of the current thread Download
						int CurrentThreadPosition = startIndex + total;
						// == Record the download location of the current thread (. txt file), define random access and file object
						// == "rwd" opens for reading and writing, and for "rw", every update to the file content is synchronously written to the underlying storage device.
						RandomAccessFile raff = new RandomAccessFile(ThreadId + ".txt", "rwd");
						raff.write(String.valueOf(CurrentThreadPosition).getBytes());
						raff.close();
					}
					// Release resources
					in.close();
					raf.close();

					System.out.println("thread" + ThreadId + "Download completed!");

					// === After each thread downloads, delete the'.txt'file of each thread, and lock the deletion operation in order to avoid concurrent operation.====
					synchronized (DownLoadThread.class) {
						RunningThread--;// Threads will not run after downloading, and the number of threads running will be reduced accordingly.
						if (RunningThread == 0) {// When the number of Running Threads is 0, all the files are downloaded.
							for (int i = 1; i <= ThreadCount; i++) {
								File deleteFile = new File(i + ".txt");
								deleteFile.delete();
							}
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	//Get the file name of the source file
	public static String getName(String path){
		//http://192.168.56.1:8080/haozip.exe
		//Get the index of the last occurrence of "/"
		int index=path.lastIndexOf("/");
		String name=path.substring(index+1);
		return name;
	}
}

Posted by raptorman on Fri, 05 Apr 2019 13:57:31 -0700