Consider this code:
package com.zip;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.Date;
import static com.diffplug.common.base.Errors.rethrow;
/**
* @author nsheremet
*/
public class ParallelDownload2 {
public static int THREADCOUNT = 20;
private static final String URL = "https://server.com/myfile.zip";
public static String OUTPUT = "C:\\!deleteme\\myfile.zip";
public static void main(String[] args) throws Exception {
System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
System.out.println(new Date());
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet request = new HttpGet(URL);
request.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36");
CloseableHttpResponse response = rethrow().wrap(() -> httpClient.execute(request)).get();
Long contentLength = Long.parseLong(response.getFirstHeader("Content-Length").getValue());
long blocksize = contentLength / THREADCOUNT;
RandomAccessFile randomAccessFile = new RandomAccessFile(new File(OUTPUT), "rwd");
randomAccessFile.setLength(contentLength);
randomAccessFile.close();
response.close();
for (long i = 0; i <THREADCOUNT; i++) {
long startpos = i * blocksize;
long endpos = (i + 1) * blocksize - 1;
if (i == THREADCOUNT - 1) {
endpos = contentLength;
}
new Thread(new DownloadTask(i, startpos, endpos)).start();
}
System.out.println(new Date());
}
public static class DownloadTask implements Runnable {
public DownloadTask(
long id,
long startpos,
long endpos
) {
this.id = id;
this.startpos = startpos;
this.endpos = endpos;
}
long id;
long startpos;
long endpos;
@Override
public void run() {
try {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet request = new HttpGet(URL);
request.addHeader("Range", "bytes=" + startpos + "-" + endpos + "");
request.addHeader("Connection", "keep-alive");
request.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36");
CloseableHttpResponse response = rethrow().wrap(() -> httpClient.execute(request)).get();
if (response.getStatusLine().getStatusCode() == 206) {
InputStream is = response.getEntity().getContent();
RandomAccessFile randomAccessFile = new RandomAccessFile(new File(OUTPUT), "rwd");
randomAccessFile.seek(startpos);
int len = 0;
byte[] buffer = new byte[1024*10];
while ((len = is.read(buffer)) != -1) {
randomAccessFile.write(buffer, 0, len);
}
is.close();
randomAccessFile.close();
System.out.println("Thread "+ Thread.currentThread().getId() +": Download");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(new Date());
}
}
}
This is a modified copy from this one which is written via simple URL.openConnection
. Why URL.openConnection
with multithreading donwload the file with 10 Mb/sec while apach http client version speed mostly between 1-5 Mb/sec? Am I missed something in http apache client settings?
UPDATED
- I use multiple HttpClients because single object leads to same performance as 1 connection via URL
- Http apache client is used in mane high performance servers ,so I believe there is definitelly configuration issue. But what exactly?
About code
This of course not production ready code and should be considered as protote where I want to make multithreading download work fast.
About nultithreading
I can not explain why because I am not owner of downloading resource but multi threading downloading speed much faster (10 times) the single thread.