О чем статья.
Цель данной статьи: написать разные варианты программы для скачивания картинок, чтобы показать множество разных способов создания многопоточных программ в Java. А конкретнее мы будем использовать такие способы:
- расширение класса Thread;
- интерфейс Runnable;
- интерфейс Callable с FutureTask;
- интерфейс Callable с ExecutorService;
- интерфейс Callable с CompletionService
- фреймворк ForkJoin;
Естественно это не все многопоточные фичи, а только некоторые из них. Но я думаю что и это будет полезно для тех кто интересуется написанием быстрых многопоточных программ на Java. Статья не претендует на полноту и совершенство, поэтому не судите строго первый блин комом ;)
Пишем код
Для начала создадим класс который будет собственно качать картинку. Назовем его, например, Loader, также создадим свой Exception для пустого url:
import com.easy.imageloader.threads.exception.EmptyURLException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Created by Andrienko Alexander on 03.07.2014.
*/
public class Loader {
private String urlLine = "";
public String getUrlLine() {
return urlLine;
}
public void setUrlLine(String urlLine) throws EmptyURLException {
if (urlLine == null || urlLine.length() == 0) {
throw new EmptyURLException("Link of image is null");
}
this.urlLine = urlLine;
}
public void load() throws IOException {
URL url = new URL(urlLine);
int begin = urlLine.lastIndexOf("/");
if (begin == -1) {
System.out.println("index of urlLine = -1");
return;
}
String name = urlLine.substring(begin + 1, urlLine.length());
Path path2 = Paths.get("images");
if (!Files.exists(path2)) {
Files.createDirectories(path2);
}
Path downloadPath = Paths.get("images\\" + name);
ReadableByteChannel rbc = Channels.newChannel(url.openStream());
FileOutputStream fos = new FileOutputStream(downloadPath.toFile());
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
}
}
/**
* Created by Andrienko Alexander on 03.07.2014.
*/
public class EmptyURLException extends Exception {
public EmptyURLException() {
super();
}
public EmptyURLException(String message) {
super(message);
}
}
Как видите, есть гетер и сеттер для того чтобы забрать или задать url картинки. Для скачки картинки нужно вызвать метод load. Он использует стандартную библиотеку nio для скачивания. Сначала мы преобразуем строку url в класс URL (инкапсулируем путь и получаем доступ к методам этого полезного класса). Дальше из ссылки "вырезаем" имя файла и сохраняем его в переменную name. Создаем путь path к папке в которой мы будем хранить скачанные картинки. Дальше проверяем существует ли она, если нет то создаем. Как вы наверное уже поняли картинки будут храниться в папке images, которая находиться в корне проекта. Дальше создаем путь по которому будем хранить картинку. Потом создаем канал rbc в который кладем поток байтов извлеченный из path. Дальше формируем поток символов FileOutputStream fos для записи у файл. И напоследок серия эффектных методов:
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
То есть мы записываем у файл с помощью потока символов fos байты из канала rbc.
Качаем 11 картинок в один поток. Медленно работает, зато писать однопоточный код проще...
Создадим файл который будет качать картинки. Качаться они будут по одной в главном потоке Main. url мы забьем хардкодом, НЕКРАСИВО, но для примера пойдет:
import com.easy.imageloader.threads.exception.EmptyURLException;
import com.easy.imageloader.threads.loader.Loader;
import java.io.IOException;
/**
* Created by Andrienko Alexander on 03.07.2014.
*/
public class ApplicationOneThreadImageLoader {
public static void main(String[] args) throws EmptyURLException, IOException {
Loader loader = new Loader();
String[] arrayLink = new String[] {
"http://upload.wikimedia.org/wikipedia/commons/9/9b/Black_Aston_Martin_DBS_fr.jpg",
"http://chudesa-mira.ru/uploads/images/00/00/21/2011/11/17/872999.jpg",
"http://unnatural.ru/wp-content/uploads/2011/04/Bugatti-Veyron-16.4-Super-Sport-1.jpg",
"http://bom.flenda.ru/images/gallery/97/327_1000x750.jpg",
"http://bom.flenda.ru/images/gallery/97/322_1000x750.jpg",
"http://img11.nnm.me/9/5/c/f/0/95cf0985d6a5b0233e01669da5fe77c9_full.jpg",
"http://img.gazeta.ru/files3/717/3990717/bmw-pic452-452x452-36449.jpg",
"http://telegraf.com.ua/files/2012/10/bmv_-x6_-sinyaya_avtomobili_mashiny_avto.jpg",
"http://pro-rap.net/uploads/posts/2013-09/1380105844_331651.jpg",
"http://original-news.ru/wp-content/uploads/2013/02/Bugatti-Veyron-Super-Sport-%D0%" +
"B4%D0%BE%D1%80%D0%BE%D0%B3%D0%BE%D0%B9-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%BE" +
"%D0%B1%D0%B8%D0%BB%D1%8C.jpg",
"http://neobychno.com/img/2011/11/1-bugatti-veyron1-revise1.jpg"
};
for (String link: arrayLink) {
loader.setUrlLine(link);
loader.load();
}
}
}
Тут все просто: создаем массив из 11 картинок, потом в цикле их качаем по одной. Этот пример я написал исключительно для сравнения. Однопоточные программы работают медленнее, чем многопоточные, но писать их легче, и всегда есть участки кода которые не поддаются эффективному розпаралеливанию, или затрата на создания потоков не оправдана (выигрыша в скорости нет, или эта часть кода должна работать последовательно).
Вариант 1 Розширяем класс Thread
Тут все просто расширяем класс Thread в котором нужно обязательно реализовать метод run();
public class ThreadImageLoader extends Thread{
String url;
public ThreadImageLoader(String url) {
super();
this.url = url;
start();
}
@Override
public void run() {
Loader loader = new Loader();
try {
loader.setUrlLine(url);
loader.load();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ApplicationThread {
public static void main(String[] args) {
ThreadImageLoader thread1 = new ThreadImageLoader("http://chudesa-mira.ru/uploads/images/00/00/21/2011/11/17/872999.jpg");
ThreadImageLoader thread2 = new ThreadImageLoader("http://unnatural.ru/wp-content/uploads/2011/04/Bugatti-Veyron-16.4-Super-Sport-1.jpg");
ThreadImageLoader thread3 = new ThreadImageLoader("http://bom.flenda.ru/images/gallery/97/327_1000x750.jpg");
ThreadImageLoader thread4 = new ThreadImageLoader("http://bom.flenda.ru/images/gallery/97/322_1000x750.jpg");
ThreadImageLoader thread5 = new ThreadImageLoader("http://img11.nnm.me/9/5/c/f/0/95cf0985d6a5b0233e01669da5fe77c9_full.jpg");
ThreadImageLoader thread6 = new ThreadImageLoader("http://img.gazeta.ru/files3/717/3990717/bmw-pic452-452x452-36449.jpg");
ThreadImageLoader thread7 = new ThreadImageLoader("http://telegraf.com.ua/files/2012/10/bmv_-x6_-sinyaya_avtomobili_mashiny_avto.jpg");
ThreadImageLoader thread8 = new ThreadImageLoader("http://pro-rap.net/uploads/posts/2013-09/1380105844_331651.jpg");
ThreadImageLoader thread9 = new ThreadImageLoader("http://original-news.ru/wp-content/uploads/2013/02/Bugatti-Veyron-Super-Sport-%D0%B4%D0%BE%D1%80%D0%BE%D0%B3%D0%BE%D0%B9-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%BE%D0%B1%D0%B8%D0%BB%D1%8C.jpg");
ThreadImageLoader thread10 = new ThreadImageLoader("http://neobychno.com/img/2011/11/1-bugatti-veyron1-revise1.jpg");
}
}
Поток запускается методом start(). Если запустить метод run, то код будет выполняться, но не в отдельном потоке, а в главном потоке, то есть ни о какой мультипоточности речь не будет идти. Код отработает последовательно. Кстати метод start() не обязательно запускать в конструкторе, это можно сделать и в точке вызова потока. Есть разные вариации создания потока через расширения класса Thread: анонимные классы в методах или конструкторах, и сделать внутренний класс который расширит Thread и т.д.
Вариант 2 Реализовываем интерфейс Runnable
Будем реализовывать интерфейс Runnable. Если вы посмотрите в конструктор то заметите что мы там создаем новый Thread поток в который через this кладем ссылку на текущий RunnableImageLoader. А дальше методом start() запускаем поток. Таким образом как-только вы создали экземпляр класса RunnableImageLoader (как говорят программисты создали инстанс) поток сразу инициализируется и запуститься на выполнение.
Вариант 2.1
/**
* Created by Andrienko Alexander on 05.07.2014.
*/
public class RunnableImageLoader implements Runnable {
String url;
Thread thread;
int i;
public RunnableImageLoader(int i, String url) {
thread = new Thread(this);
this.url = url;
thread.start();
this.i = i;
}
@Override
public void run() {
Loader loader = new Loader();
try {
loader.setUrlLine(url);
loader.load();
System.out.println(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Created by Andrienko Alexander on 17.08.2014.
*/
* Created by Andrienko Alexander on 17.08.2014.
*/
public class ApplicationRunnable {
public static void main(String[] args) {
RunnableImageLoader thread1 = new RunnableImageLoader(1, "http://chudesa-mira.ru/uploads/images/00/00/21/2011/11/17/872999.jpg");
RunnableImageLoader thread2 = new RunnableImageLoader(2, "http://unnatural.ru/wp-content/uploads/2011/04/Bugatti-Veyron-16.4-Super-Sport-1.jpg");
RunnableImageLoader thread3 = new RunnableImageLoader(3, "http://bom.flenda.ru/images/gallery/97/327_1000x750.jpg");
RunnableImageLoader thread4 = new RunnableImageLoader(4, "http://bom.flenda.ru/images/gallery/97/322_1000x750.jpg");
RunnableImageLoader thread5 = new RunnableImageLoader(5, "http://img11.nnm.me/9/5/c/f/0/95cf0985d6a5b0233e01669da5fe77c9_full.jpg");
RunnableImageLoader thread6 = new RunnableImageLoader(6, "http://img.gazeta.ru/files3/717/3990717/bmw-pic452-452x452-36449.jpg");
RunnableImageLoader thread7 = new RunnableImageLoader(7, "http://telegraf.com.ua/files/2012/10/bmv_-x6_-sinyaya_avtomobili_mashiny_avto.jpg");
RunnableImageLoader thread8 = new RunnableImageLoader(8, "http://pro-rap.net/uploads/posts/2013-09/1380105844_331651.jpg");
RunnableImageLoader thread9 = new RunnableImageLoader(9, "http://original-news.ru/wp-content/uploads/2013/02/Bugatti-Veyron-Super-Sport-%D0%B4%D0%BE%D1%80%D0%BE%D0%B3%D0%BE%D0%B9-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%BE%D0%B1%D0%B8%D0%BB%D1%8C.jpg");
RunnableImageLoader thread10 = new RunnableImageLoader(10,"http://neobychno.com/img/2011/11/1-bugatti-veyron1-revise1.jpg");
}
}
Вариант 2.2
/**
* Created by Andrienko Alexander on 17.08.2014.
*/
public class RunnableImageLoader2 implements Runnable{
String url;
public RunnableImageLoader2(String url){
this.url = url;
}
@Override
public void run() {
Loader loader = new Loader();
try {
loader.setUrlLine(url);
loader.load();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Вариант 2.3
String url;
Thread thread;
public RunnableImageLoader3(String url) {
thread = new Thread(this);
this.url = url;
}
public void start() {
thread.start();
}
@Override
public void run() {
Loader loader = new Loader();
try {
loader.setUrlLine(url);
loader.load();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Created by Andrienko Alexander on 17.08.2014.
*/
public class RunnableImageLoader3 implements Runnable{String url;
Thread thread;
public RunnableImageLoader3(String url) {
thread = new Thread(this);
this.url = url;
}
public void start() {
thread.start();
}
@Override
public void run() {
Loader loader = new Loader();
try {
loader.setUrlLine(url);
loader.load();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Created by Andrienko Alexander on 17.08.2014.
*/
public class ApplicationRunnable3 {
public static void main(String[] args) {
RunnableImageLoader3 thread1 = new RunnableImageLoader3("http://chudesa-mira.ru/uploads/images/00/00/21/2011/11/17/872999.jpg");
thread1.start();
RunnableImageLoader3 thread2 = new RunnableImageLoader3("http://unnatural.ru/wp-content/uploads/2011/04/Bugatti-Veyron-16.4-Super-Sport-1.jpg");
thread2.start();
RunnableImageLoader3 thread3 = new RunnableImageLoader3("http://bom.flenda.ru/images/gallery/97/327_1000x750.jpg");
thread3.start();
RunnableImageLoader3 thread4 = new RunnableImageLoader3("http://bom.flenda.ru/images/gallery/97/322_1000x750.jpg");
thread4.start();
RunnableImageLoader3 thread5 = new RunnableImageLoader3("http://img11.nnm.me/9/5/c/f/0/95cf0985d6a5b0233e01669da5fe77c9_full.jpg");
thread5.start();
RunnableImageLoader3 thread6 = new RunnableImageLoader3("http://img.gazeta.ru/files3/717/3990717/bmw-pic452-452x452-36449.jpg");
thread6.start();
RunnableImageLoader3 thread7 = new RunnableImageLoader3("http://telegraf.com.ua/files/2012/10/bmv_-x6_-sinyaya_avtomobili_mashiny_avto.jpg");
thread7.start();
RunnableImageLoader3 thread8 = new RunnableImageLoader3("http://pro-rap.net/uploads/posts/2013-09/1380105844_331651.jpg");
thread8.start();
RunnableImageLoader3 thread9 = new RunnableImageLoader3("http://original-news.ru/wp-content/uploads/2013/02/Bugatti-Veyron-Super-Sport-%D0%B4%D0%BE%D1%80%D0%BE%D0%B3%D0%BE%D0%B9-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%BE%D0%B1%D0%B8%D0%BB%D1%8C.jpg");
thread9.start();
RunnableImageLoader3 thread10 = new RunnableImageLoader3("http://neobychno.com/img/2011/11/1-bugatti-veyron1-revise1.jpg");
thread10.start();
}
}
Вариант 3 Реализовываем интерфейс Сallable
Callable это тоже интерфейс но в отличие от Runnable, он может возвращать результат своей роботы и не поглощает Exception. Под поглощение нужно понимать что в Runnable мы не можем выбросить Exception из метода run(), мы должны внутри его обработать с помощью try-catch. Код Callable приведу одни раз но дам сразу несколько способов как его можно запустить.
/**
* Created by Andrienko Alexander on 17.08.2014.
*/
* Created by Andrienko Alexander on 17.08.2014.
*/
public class CallableImageLoader implements Callable<String> {
private String url;
private int i;
public CallableImageLoader(int i, String url) {
this.url = url;
this.i = i;
}
@Override
public String call() throws Exception {
Loader loader = new Loader();
loader.setUrlLine(url);
loader.load();
System.out.println(i);
return "Loading image complete" + i;
}
}
Можно запустить используя обертку FutureTask.
/**
* Created by Andrienko Alexander on 17.08.2014.
*/
public class ApplicationCallableWithFutureTask {
public static void main(String[] args) {
List<FutureTask<String>> futureTasks = new LinkedList<FutureTask<String>>(
Arrays.asList(
new FutureTask<String>(new CallableImageLoader(1,"http://chudesa-mira.ru/uploads/images/00/00/21/2011/11/17/872999.jpg")),
new FutureTask<String>(new CallableImageLoader(2, "http://unnatural.ru/wp-content/uploads/2011/04/Bugatti-Veyron-16.4-Super-Sport-1.jpg")),
new FutureTask<String>(new CallableImageLoader(3, "http://bom.flenda.ru/images/gallery/97/327_1000x750.jpg")),
new FutureTask<String>(new CallableImageLoader(4, "http://bom.flenda.ru/images/gallery/97/322_1000x750.jpg")),
new FutureTask<String>(new CallableImageLoader(5, "http://img11.nnm.me/9/5/c/f/0/95cf0985d6a5b0233e01669da5fe77c9_full.jpg")),
new FutureTask<String>(new CallableImageLoader(6, "http://img.gazeta.ru/files3/717/3990717/bmw-pic452-452x452-36449.jpg")),
new FutureTask<String>(new CallableImageLoader(7, "http://telegraf.com.ua/files/2012/10/bmv_-x6_-sinyaya_avtomobili_mashiny_avto.jpg")),
new FutureTask<String>(new CallableImageLoader(8, "http://pro-rap.net/uploads/posts/2013-09/1380105844_331651.jpg")),
new FutureTask<String>(new CallableImageLoader(9, "http://original-news.ru/wp-content/uploads/2013/02/Bugatti-Veyron-Super-Sport-%D0%B4%D0%BE%D1%80%D0%BE%D0%B3%D0%BE%D0%B9-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%BE%D0%B1%D0%B8%D0%BB%D1%8C.jpg")),
new FutureTask<String>(new CallableImageLoader(10, "http://neobychno.com/img/2011/11/1-bugatti-veyron1-revise1.jpg"))
)
);
for(FutureTask<String> task: futureTasks) {
new Thread(task).start();
}
for (FutureTask<String> task: futureTasks) {
try {
System.out.println(task.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
Можно запустить через CompletionService.
/**
* Created by USER on 19.08.2014.
*/
public class ApplicationCompletionService {
public static void main(String[] args) throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(10);
List<CallableImageLoader> listThreads = new ArrayList<CallableImageLoader>(
Arrays.asList(
new CallableImageLoader(1, "http://unnatural.ru/wp-content/uploads/2011/04/Bugatti-Veyron-16.4-Super-Sport-1.jpg"),
new CallableImageLoader(2, "http://bom.flenda.ru/images/gallery/97/327_1000x750.jpg"),
new CallableImageLoader(3, "http://bom.flenda.ru/images/gallery/97/322_1000x750.jpg"),
new CallableImageLoader(4, "http://img11.nnm.me/9/5/c/f/0/95cf0985d6a5b0233e01669da5fe77c9_full.jpg"),
new CallableImageLoader(5, "http://img.gazeta.ru/files3/717/3990717/bmw-pic452-452x452-36449.jpg"),
new CallableImageLoader(6, "http://telegraf.com.ua/files/2012/10/bmv_-x6_-sinyaya_avtomobili_mashiny_avto.jpg"),
new CallableImageLoader(7, "http://pro-rap.net/uploads/posts/2013-09/1380105844_331651.jpg"),
new CallableImageLoader(8, "http://original-news.ru/wp-content/uploads/2013/02/Bugatti-Veyron-Super-Sport-%D0%B4%D0%BE%D1%80%D0%BE%D0%B3%D0%BE%D0%B9-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%BE%D0%B1%D0%B8%D0%BB%D1%8C.jpg"),
new CallableImageLoader(9, "http://chudesa-mira.ru/uploads/images/00/00/21/2011/11/17/872999.jpg"),
new CallableImageLoader(10, "http://neobychno.com/img/2011/11/1-bugatti-veyron1-revise1.jpg")
)
);
CompletionService<String> completionService = new ExecutorCompletionService(service);
for (CallableImageLoader elem: listThreads) {
if (elem instanceof Callable) {
completionService.submit(elem);
}
}
for (int i = 0; i < 10; i++) {
try {
String result = completionService.take().get().toString();
System.out.println("result is " + result);
} catch (ExecutionException e) {
e.printStackTrace();
}
}
service.shutdown();
}
}
Можно через ExecutorService:
/**
* Created by Andrienko Alexander on 09.07.2014.
*/
public class ApplicationCallable {
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(10);
List<Future> listFutures = new LinkedList<>();
listFutures.add(es.submit(new CallableImageLoader(1, "http://chudesa-mira.ru/uploads/images/00/00/21/2011/11/17/872999.jpg")));
listFutures.add(es.submit(new CallableImageLoader(2, "http://unnatural.ru/wp-content/uploads/2011/04/Bugatti-Veyron-16.4-Super-Sport-1.jpg")));
listFutures.add(es.submit(new CallableImageLoader(3, "http://bom.flenda.ru/images/gallery/97/327_1000x750.jpg")));
listFutures.add(es.submit(new CallableImageLoader(4, "http://bom.flenda.ru/images/gallery/97/322_1000x750.jpg")));
listFutures.add(es.submit(new CallableImageLoader(5, "http://img11.nnm.me/9/5/c/f/0/95cf0985d6a5b0233e01669da5fe77c9_full.jpg")));
listFutures.add(es.submit(new CallableImageLoader(6, "http://img.gazeta.ru/files3/717/3990717/bmw-pic452-452x452-36449.jpg")));
listFutures.add(es.submit(new CallableImageLoader(7, "http://telegraf.com.ua/files/2012/10/bmv_-x6_-sinyaya_avtomobili_mashiny_avto.jpg")));
listFutures.add(es.submit(new CallableImageLoader(8, "http://pro-rap.net/uploads/posts/2013-09/1380105844_331651.jpg")));
listFutures.add(es.submit(new CallableImageLoader(9, "http://original-news.ru/wp-content/uploads/2013/02/Bugatti-Veyron-Super-Sport-%D0%B4%D0%BE%D1%80%D0%BE%D0%B3%D0%BE%D0%B9-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%BE%D0%B1%D0%B8%D0%BB%D1%8C.jpg")));
listFutures.add(es.submit(new CallableImageLoader(10, "http://neobychno.com/img/2011/11/1-bugatti-veyron1-revise1.jpg")));
for (Future future: listFutures) {
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
es.shutdown();
}
}
и снова же через ExecutorService но не через newFixedThreadPool а через newCachedThreadPool :
/**
* Created by Andrienko Alexander on 09.07.2014.
*/
public class ApplicationCallable {
public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool();
List<Future> listFutures = new LinkedList<>();
listFutures.add(es.submit(new CallableImageLoader(1, "http://chudesa-mira.ru/uploads/images/00/00/21/2011/11/17/872999.jpg")));
listFutures.add(es.submit(new CallableImageLoader(2, "http://unnatural.ru/wp-content/uploads/2011/04/Bugatti-Veyron-16.4-Super-Sport-1.jpg")));
listFutures.add(es.submit(new CallableImageLoader(3, "http://bom.flenda.ru/images/gallery/97/327_1000x750.jpg")));
listFutures.add(es.submit(new CallableImageLoader(4, "http://bom.flenda.ru/images/gallery/97/322_1000x750.jpg")));
listFutures.add(es.submit(new CallableImageLoader(5, "http://img11.nnm.me/9/5/c/f/0/95cf0985d6a5b0233e01669da5fe77c9_full.jpg")));
listFutures.add(es.submit(new CallableImageLoader(6, "http://img.gazeta.ru/files3/717/3990717/bmw-pic452-452x452-36449.jpg")));
listFutures.add(es.submit(new CallableImageLoader(7, "http://telegraf.com.ua/files/2012/10/bmv_-x6_-sinyaya_avtomobili_mashiny_avto.jpg")));
listFutures.add(es.submit(new CallableImageLoader(8, "http://pro-rap.net/uploads/posts/2013-09/1380105844_331651.jpg")));
listFutures.add(es.submit(new CallableImageLoader(9, "http://original-news.ru/wp-content/uploads/2013/02/Bugatti-Veyron-Super-Sport-%D0%B4%D0%BE%D1%80%D0%BE%D0%B3%D0%BE%D0%B9-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%BE%D0%B1%D0%B8%D0%BB%D1%8C.jpg")));
listFutures.add(es.submit(new CallableImageLoader(10, "http://neobychno.com/img/2011/11/1-bugatti-veyron1-revise1.jpg")));
for (Future future: listFutures) {
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
es.shutdown();
}
}
Думаю достаточно, список "можно" и так длинный...
private String url;
private int i;
public CallableImageLoader(int i, String url) {
this.url = url;
this.i = i;
}
@Override
public String call() throws Exception {
Loader loader = new Loader();
loader.setUrlLine(url);
loader.load();
System.out.println(i);
return "Loading image complete" + i;
}
}
Можно запустить используя обертку FutureTask.
/**
* Created by Andrienko Alexander on 17.08.2014.
*/
public class ApplicationCallableWithFutureTask {
public static void main(String[] args) {
List<FutureTask<String>> futureTasks = new LinkedList<FutureTask<String>>(
Arrays.asList(
new FutureTask<String>(new CallableImageLoader(1,"http://chudesa-mira.ru/uploads/images/00/00/21/2011/11/17/872999.jpg")),
new FutureTask<String>(new CallableImageLoader(2, "http://unnatural.ru/wp-content/uploads/2011/04/Bugatti-Veyron-16.4-Super-Sport-1.jpg")),
new FutureTask<String>(new CallableImageLoader(3, "http://bom.flenda.ru/images/gallery/97/327_1000x750.jpg")),
new FutureTask<String>(new CallableImageLoader(4, "http://bom.flenda.ru/images/gallery/97/322_1000x750.jpg")),
new FutureTask<String>(new CallableImageLoader(5, "http://img11.nnm.me/9/5/c/f/0/95cf0985d6a5b0233e01669da5fe77c9_full.jpg")),
new FutureTask<String>(new CallableImageLoader(6, "http://img.gazeta.ru/files3/717/3990717/bmw-pic452-452x452-36449.jpg")),
new FutureTask<String>(new CallableImageLoader(7, "http://telegraf.com.ua/files/2012/10/bmv_-x6_-sinyaya_avtomobili_mashiny_avto.jpg")),
new FutureTask<String>(new CallableImageLoader(8, "http://pro-rap.net/uploads/posts/2013-09/1380105844_331651.jpg")),
new FutureTask<String>(new CallableImageLoader(9, "http://original-news.ru/wp-content/uploads/2013/02/Bugatti-Veyron-Super-Sport-%D0%B4%D0%BE%D1%80%D0%BE%D0%B3%D0%BE%D0%B9-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%BE%D0%B1%D0%B8%D0%BB%D1%8C.jpg")),
new FutureTask<String>(new CallableImageLoader(10, "http://neobychno.com/img/2011/11/1-bugatti-veyron1-revise1.jpg"))
)
);
for(FutureTask<String> task: futureTasks) {
new Thread(task).start();
}
for (FutureTask<String> task: futureTasks) {
try {
System.out.println(task.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
Можно запустить через CompletionService.
/**
* Created by USER on 19.08.2014.
*/
public class ApplicationCompletionService {
public static void main(String[] args) throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(10);
List<CallableImageLoader> listThreads = new ArrayList<CallableImageLoader>(
Arrays.asList(
new CallableImageLoader(1, "http://unnatural.ru/wp-content/uploads/2011/04/Bugatti-Veyron-16.4-Super-Sport-1.jpg"),
new CallableImageLoader(2, "http://bom.flenda.ru/images/gallery/97/327_1000x750.jpg"),
new CallableImageLoader(3, "http://bom.flenda.ru/images/gallery/97/322_1000x750.jpg"),
new CallableImageLoader(4, "http://img11.nnm.me/9/5/c/f/0/95cf0985d6a5b0233e01669da5fe77c9_full.jpg"),
new CallableImageLoader(5, "http://img.gazeta.ru/files3/717/3990717/bmw-pic452-452x452-36449.jpg"),
new CallableImageLoader(6, "http://telegraf.com.ua/files/2012/10/bmv_-x6_-sinyaya_avtomobili_mashiny_avto.jpg"),
new CallableImageLoader(7, "http://pro-rap.net/uploads/posts/2013-09/1380105844_331651.jpg"),
new CallableImageLoader(8, "http://original-news.ru/wp-content/uploads/2013/02/Bugatti-Veyron-Super-Sport-%D0%B4%D0%BE%D1%80%D0%BE%D0%B3%D0%BE%D0%B9-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%BE%D0%B1%D0%B8%D0%BB%D1%8C.jpg"),
new CallableImageLoader(9, "http://chudesa-mira.ru/uploads/images/00/00/21/2011/11/17/872999.jpg"),
new CallableImageLoader(10, "http://neobychno.com/img/2011/11/1-bugatti-veyron1-revise1.jpg")
)
);
CompletionService<String> completionService = new ExecutorCompletionService(service);
for (CallableImageLoader elem: listThreads) {
if (elem instanceof Callable) {
completionService.submit(elem);
}
}
for (int i = 0; i < 10; i++) {
try {
String result = completionService.take().get().toString();
System.out.println("result is " + result);
} catch (ExecutionException e) {
e.printStackTrace();
}
}
service.shutdown();
}
}
Можно через ExecutorService:
/**
* Created by Andrienko Alexander on 09.07.2014.
*/
public class ApplicationCallable {
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(10);
List<Future> listFutures = new LinkedList<>();
listFutures.add(es.submit(new CallableImageLoader(1, "http://chudesa-mira.ru/uploads/images/00/00/21/2011/11/17/872999.jpg")));
listFutures.add(es.submit(new CallableImageLoader(2, "http://unnatural.ru/wp-content/uploads/2011/04/Bugatti-Veyron-16.4-Super-Sport-1.jpg")));
listFutures.add(es.submit(new CallableImageLoader(3, "http://bom.flenda.ru/images/gallery/97/327_1000x750.jpg")));
listFutures.add(es.submit(new CallableImageLoader(4, "http://bom.flenda.ru/images/gallery/97/322_1000x750.jpg")));
listFutures.add(es.submit(new CallableImageLoader(5, "http://img11.nnm.me/9/5/c/f/0/95cf0985d6a5b0233e01669da5fe77c9_full.jpg")));
listFutures.add(es.submit(new CallableImageLoader(6, "http://img.gazeta.ru/files3/717/3990717/bmw-pic452-452x452-36449.jpg")));
listFutures.add(es.submit(new CallableImageLoader(7, "http://telegraf.com.ua/files/2012/10/bmv_-x6_-sinyaya_avtomobili_mashiny_avto.jpg")));
listFutures.add(es.submit(new CallableImageLoader(8, "http://pro-rap.net/uploads/posts/2013-09/1380105844_331651.jpg")));
listFutures.add(es.submit(new CallableImageLoader(9, "http://original-news.ru/wp-content/uploads/2013/02/Bugatti-Veyron-Super-Sport-%D0%B4%D0%BE%D1%80%D0%BE%D0%B3%D0%BE%D0%B9-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%BE%D0%B1%D0%B8%D0%BB%D1%8C.jpg")));
listFutures.add(es.submit(new CallableImageLoader(10, "http://neobychno.com/img/2011/11/1-bugatti-veyron1-revise1.jpg")));
for (Future future: listFutures) {
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
es.shutdown();
}
}
и снова же через ExecutorService но не через newFixedThreadPool а через newCachedThreadPool :
/**
* Created by Andrienko Alexander on 09.07.2014.
*/
public class ApplicationCallable {
public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool();
List<Future> listFutures = new LinkedList<>();
listFutures.add(es.submit(new CallableImageLoader(1, "http://chudesa-mira.ru/uploads/images/00/00/21/2011/11/17/872999.jpg")));
listFutures.add(es.submit(new CallableImageLoader(2, "http://unnatural.ru/wp-content/uploads/2011/04/Bugatti-Veyron-16.4-Super-Sport-1.jpg")));
listFutures.add(es.submit(new CallableImageLoader(3, "http://bom.flenda.ru/images/gallery/97/327_1000x750.jpg")));
listFutures.add(es.submit(new CallableImageLoader(4, "http://bom.flenda.ru/images/gallery/97/322_1000x750.jpg")));
listFutures.add(es.submit(new CallableImageLoader(5, "http://img11.nnm.me/9/5/c/f/0/95cf0985d6a5b0233e01669da5fe77c9_full.jpg")));
listFutures.add(es.submit(new CallableImageLoader(6, "http://img.gazeta.ru/files3/717/3990717/bmw-pic452-452x452-36449.jpg")));
listFutures.add(es.submit(new CallableImageLoader(7, "http://telegraf.com.ua/files/2012/10/bmv_-x6_-sinyaya_avtomobili_mashiny_avto.jpg")));
listFutures.add(es.submit(new CallableImageLoader(8, "http://pro-rap.net/uploads/posts/2013-09/1380105844_331651.jpg")));
listFutures.add(es.submit(new CallableImageLoader(9, "http://original-news.ru/wp-content/uploads/2013/02/Bugatti-Veyron-Super-Sport-%D0%B4%D0%BE%D1%80%D0%BE%D0%B3%D0%BE%D0%B9-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%BE%D0%B1%D0%B8%D0%BB%D1%8C.jpg")));
listFutures.add(es.submit(new CallableImageLoader(10, "http://neobychno.com/img/2011/11/1-bugatti-veyron1-revise1.jpg")));
for (Future future: listFutures) {
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
es.shutdown();
}
}
Думаю достаточно, список "можно" и так длинный...
Вариант 4 Используем фреймворк ForkJoin
Ну тут сразу, код:
/**
* Created by Andrienko Alexander on 09.07.2014.
*/
public class ForkJoinTaskImageLoader extends RecursiveAction{
private String url;
private int i;
public ForkJoinTaskImageLoader(int i, String url) {
this.url = url;
this.i = i;
}
@Override
protected void compute() {
Loader loader = new Loader();
try {
loader.setUrlLine(url);
loader.load();
} catch (Exception e) {
System.out.println(e);
}
System.out.println(i);
}
}
public class ApplicationForkJoin {
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool(4);
forkJoinPool.execute(new ForkJoinTaskImageLoader(1, "http://chudesa-mira.ru/uploads/images/00/00/21/2011/11/17/872999.jpg"));
forkJoinPool.execute(new ForkJoinTaskImageLoader(2, "http://unnatural.ru/wp-content/uploads/2011/04/Bugatti-Veyron-16.4-Super-Sport-1.jpg"));
forkJoinPool.execute(new ForkJoinTaskImageLoader(3, "http://bom.flenda.ru/images/gallery/97/327_1000x750.jpg"));
forkJoinPool.execute(new ForkJoinTaskImageLoader(4, "http://bom.flenda.ru/images/gallery/97/322_1000x750.jpg"));
forkJoinPool.execute(new ForkJoinTaskImageLoader(5, "http://img11.nnm.me/9/5/c/f/0/95cf0985d6a5b0233e01669da5fe77c9_full.jpg"));
forkJoinPool.execute(new ForkJoinTaskImageLoader(6, "http://img.gazeta.ru/files3/717/3990717/bmw-pic452-452x452-36449.jpg"));
forkJoinPool.execute(new ForkJoinTaskImageLoader(7, "http://telegraf.com.ua/files/2012/10/bmv_-x6_-sinyaya_avtomobili_mashiny_avto.jpg"));
forkJoinPool.execute(new ForkJoinTaskImageLoader(8, "http://pro-rap.net/uploads/posts/2013-09/1380105844_331651.jpg"));
forkJoinPool.execute(new ForkJoinTaskImageLoader(9, "http://original-news.ru/wp-content/uploads/2013/02/Bugatti-Veyron-Super-Sport-%D0%B4%D0%BE%D1%80%D0%BE%D0%B3%D0%BE%D0%B9-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%BE%D0%B1%D0%B8%D0%BB%D1%8C.jpg"));
forkJoinPool.execute(new ForkJoinTaskImageLoader(10, "http://neobychno.com/img/2011/11/1-bugatti-veyron1-revise1.jpg"));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Извиняюсь что не дал исчерпывающего объяснения всего кода, постараюсь дополнить статью когда появиться свободное время. Ссылка для скачки исходников на github :
PS: да я знаю что если уже и хардкодить то ссылки на картинки нужно было вынести отдельно, кода было бы меньше и читабельность повысилась бы, скоро исправлю.