Удобство
Да, многопоточность в яве действительно сделана хорошо. Инструменты удобны и если хочется получить какой-то высокоуровневый инструмент для многопоточной программы, то он существует (а если нет, то один из существующих наверняка лучше того, который хотелось увидеть).
Простой пример:
Метод submit принимает класс, реализующий интерфейс Callable и возвращает параметризированный типом результата выполнения потока Future. По сути Future - обёртка для результата потока, который можно получить методом get(). При этом если поток уже успел выполниться, то результат возвращается сразу. Если же нет, то происходит ожидание потока, в связи с чем метод get() надо вызывать аккуратно. Например, в представленной версии кода метод вызывается последовательно для каждого потока. Представим ситуацию, что второй поток выполняется 20 секунд, а третий 5. Тогда несмотря на то, что 3ий уже готов предоставить результат, мы будем ещё 15 секунд ждать ответа от потока №2. Чтобы обойти эту ситуацию нужно воспользоваться методом isDone() класса Future, который сообщит о готовности незамедлительно предоставить результат.
Что такое этот Callable?
А результат?
Стоит сказать. что сайты для примера выбраны не абы как:). Если страницы гугла и яндекса занимают в районе 10 Кб, то страница yahoo аж 127, что увеличивает время создания файла, естественно. Но нам это на руку - тем очевиднее будет многопоточность. Вывод, разумеется, разнится от запуска к запуску. Вот у меня, например, такой:
В общем, даже базовый инструментарий очень удобен, что уж говорить об объектах синхронизации, позволяющих решать более сложные задачи.
Да, многопоточность в яве действительно сделана хорошо. Инструменты удобны и если хочется получить какой-то высокоуровневый инструмент для многопоточной программы, то он существует (а если нет, то один из существующих наверняка лучше того, который хотелось увидеть).
Простой пример:
private static String[] sites =
{"www.google.com", "www.ya.ru", "www.yahoo.com"};
//создание пула потоков
ExecutorService service = Executors.newCachedThreadPool();
List<Future<String>> futures =
new ArrayList<Future<String>>();
for (int i = 0; i < sites.length; ++i) {
//запуск нового потока с параметром из массива
Future<String> future =
service.submit(new ThreadWorker(sites[i]));
futures.add(future);
}
//на этом этапе все потоки запущены
System.out.println("threads started");
for (Future<String> future : futures) {
//забираем результат выполнения потока
//если поток ещё не завершился, то происходит ожидание
System.out.println("get result from Future: " + future.get());
}
//сообщаем пулу о том, что закончили пользоваться потоками
service.shutdown();
Подробнее?Метод submit принимает класс, реализующий интерфейс Callable и возвращает параметризированный типом результата выполнения потока Future. По сути Future - обёртка для результата потока, который можно получить методом get(). При этом если поток уже успел выполниться, то результат возвращается сразу. Если же нет, то происходит ожидание потока, в связи с чем метод get() надо вызывать аккуратно. Например, в представленной версии кода метод вызывается последовательно для каждого потока. Представим ситуацию, что второй поток выполняется 20 секунд, а третий 5. Тогда несмотря на то, что 3ий уже готов предоставить результат, мы будем ещё 15 секунд ждать ответа от потока №2. Чтобы обойти эту ситуацию нужно воспользоваться методом isDone() класса Future, который сообщит о готовности незамедлительно предоставить результат.
Что такое этот Callable?
public class ThreadWorker implements Callable<String> {
private String url;
public ThreadWorker(String url) {
this.url = url;
}
public String call() throws Exception {
//открываем соединение
URLConnection connection =
new URL("http://" + url).openConnection();
PrintWriter fileWriter = new PrintWriter(url);
BufferedReader reader =
new BufferedReader(
new InputStreamReader(connection.getInputStream()));
String inputLine = reader.readLine();
//записываем все содержимое в файл
while (inputLine != null) {
fileWriter.print(inputLine);
inputLine = reader.readLine();
}
fileWriter.close();
reader.close();
System.out.println("file created " + url);
//файл создан! можно вернуть строку с адресом ресурса
String ret = url + " " + connection.getContentType();
return ret;
}
}
Как видно, ничего сложного. Перекрываемый метод call, который и является новым потоком. Возвращает он тот тип, которым параметризован Callable. В данном случае это String. В этом примере мы лезем на сайт, скачиваем страничку в файл и рапортуем об этом в консоль. Затем возвращает имя ресурса и тип контента.А результат?
Стоит сказать. что сайты для примера выбраны не абы как:). Если страницы гугла и яндекса занимают в районе 10 Кб, то страница yahoo аж 127, что увеличивает время создания файла, естественно. Но нам это на руку - тем очевиднее будет многопоточность. Вывод, разумеется, разнится от запуска к запуску. Вот у меня, например, такой:
threads started file created www.ya.ru file created www.google.com get result from Future: www.google.com text/html; charset=windows-1251 get result from Future: www.ya.ru text/html; charset=UTF-8 file created www.yahoo.com get result from Future: www.yahoo.com text/html;charset=utf-8Здесь видно, что несмотря на то, что гугл стоит первым в массиве, страничка яндекса скачалась быстрее (у меня пинг до яндекса в 2 раза ниже, чем до гугла, думаю, связано прежде всего с этим). Более того: даже ответ с типом контента от этих потоков пришёл и обработался во 2 цикле главной части быстрее, чем создался файл от yahoo.
В общем, даже базовый инструментарий очень удобен, что уж говорить об объектах синхронизации, позволяющих решать более сложные задачи.
гойЪ)
ОтветитьУдалитьприСАЪединяюсьЪ
ОтветитьУдалить