Чтение онлайн

на главную - закладки

Жанры

Философия Java3

Эккель Брюс

Шрифт:

Модель потоков (и ее поддержка в языке Java) является программным механизмом, упрощающим одновременное выполнение нескольких операций в одной и той же программе. Процессор периодически вмешивается в происходящие события, выделяя каждому потоку некоторой отрезок времени. Для каждого потока все выглядит так, словно процессор используется в монопольном режиме, но на самом деле время процессора разделяется между всеми существующими в программе потоками (исключение составляет ситуация, когда программа действительно выполняется на многопроцессорном компьютере). Однако при использовании потоков вам не нужно задумываться об этих тонкостях — код не зависит от того, на скольких процессорах

вам придется работать. Таким образом, потоки предоставляют механизм масштабирования производительности — если программа работает слишком медленно, вы в силах легко ускорить ее, установив на компьютер дополнительные процессоры. Многозадачность и многопоточность являются, похоже, наиболее вескими причинами использования многопроцессорных систем.

Задачи

Программный поток представляет некоторую задачу или операцию, поэтому нам понадобятся средства для описания этой задачи. Их предоставляет интерфейс Runnable. Чтобы определить задачу, реализуйте Runnable и напишите метод run, содержащий код выполнения нужных действий.

Например, задача LiftOff выводит обратный отсчет перед стартом:

//• concurrency/LiftOff java

// Реализация интерфейса Runnable

public class LiftOff implements Runnable {

protected int countDown =10; // Значение по умолчанию

private static int taskCount = 0,

private final int id = taskCount++;

public LiftOffО {}

public LiftOff(int countDown) {

this countDown = countDown;

}

public String status О {

return "#" + id + "(" +

(countDown > 0 ? countDown : "Liftoff!") + "), ";

}

public void run {

while(countDown-- > 0) {

System.out.pri nt(status); Thread.yieldO;

}

}

} ///:-

По идентификатору id различаются экземпляры задачи. Поле объявлено с ключевым словом final, поскольку оно не будет изменяться после инициализации.

Метод run обычно содержит некоторый цикл, который продолжает выполняться до тех пор, пока не будет достигнуто некоторое завершающее условие. Следовательно, вы должны задать условие выхода из цикла (например, просто вернуть управление командой return). Часто run выполняется в виде бесконечного цикла, а это означает, что при отсутствии завершающего условия выполнение будет продолжаться бесконечно (позднее в этой главе вы узнаете, как организовать безопасное завершение задач).

Вызов статического метода Thread.yield в run обращен к планировщику потоков (часть потокового механизма Java, обеспечивающая переключение процессора между потоками). Фактически он означает, что очередная важная часть цикла была выполнена и теперь можно на время переключиться на другую задачу. Вызов yield не обязателен, но в данном примере он обеспечивает более интересные результаты: вы с большей вероятностью увидите, что программный поток прерывает и возобновляет свою работу.

В следующем примере метод run не выделяется в отдельный программный поток, а просто вызывается напрямую в main (впрочем, поток все же используется — тот, который всегда создается для main):

//: concurrency/MainThread.java

public class MainThread {

public static void main(String[] args) { Liftoff launch = new LiftOffO; launch.run;

}

} /* Output-

#0(9). #0(8). #0(7), #0(6). #0(5). #0(4). #0(3). #0(2). #0(1). #0(Liftoff!).

*///:-

Класс, реализующий Runnable, должен содержать метод run, но ничего особенного в этом методе нет — он не обладает никакими особыми потоковыми возможностями. Чтобы использовать многопоточное выполнение, необходимо явно связать задачу с потоком.

Класс Thread

Традиционный

способ преобразования объекта Runnable в задачу заключается в передаче его конструктору Thread. Следующий пример показывает, как организовать выполнение LiftOff с использованием Thread:

//: concurrency/BasicThreads.java

// Простейший вариант использования класса Thread.

public class BasicThreads { public static void main(String[] args) { Thread t = new Thread (new LiftOffO); t.startO;

System.out.println("Waiting for LiftOff");

}

} /* Output: (90* match)

Waiting for LiftOff

#0(9). #0(8). #0(7). #0(6). #0(5). #0(4). #0(3). #0(2). #0(1). #0(Liftoff!).

*///:-

Конструктору Thread передается только объект Runnable. Метод start выполняет необходимую инициализацию потока, после чего вызов метода run интерфейса Runnable запускает задачу на выполнение в новом потоке.

Из выходных данных видно, что вызов start быстро возвращает управление (сообщение «Waiting for LiftOff» появляется до завершения отсчета). В сущности, мы вызываем LiftOff.runQ, а этот метод еще не завершил свое выполнение;

но, поскольку LiftOff.run выполняется в другом потоке, в потоке main в это время можно выполнять другие операции. (Данная возможность не ограничивается потоком main — любой поток может запустить другой поток.) Получается, что программа выполняет два метода сразу — main и LiftOff. run.

В программе можно легко породить дополнительные потоки для выполнения дополнительных задач:

// concurrency/MoreBasicThreads java

// Добавление новых потоков

public class MoreBasicThreads {

public static void main(String[] args) { for(int i = 0, l < 5, i++)

new Thread(new LiftOffO) startO. System.out println("Waiting for LiftOff"),

#2(7), #3(7) #4(5), #0(4) #1(2), #2(2) #l(Liftoff!) *///:-#4(7), #0(6) #1(4), #2(4) #3(2), #4(2) #2(Liftoff!) #4(9), #0(8) #1(6), #2(6) #3(4), #4(4) #0(1), #1(1) #3(Liftoff!) #1(8), #2(8) #3(6), #4(6) #0(3), #1(3) #2(1), #3(1) #4(Liftoff!)

#3(8), #4(8). #0(7). #1(7).

#0(5), #1(5). #2(5). #3(5),

#2(3), #3(3). #4(3). #0(2).

#4(1), #0(Liftoff!),

} /* Output. (Пример) Waiting for LiftOff #0(9), #1(9), #2(9), #3(9)

Из выходных данных видно, что задачи выполняются одновременно друг с другом, с поочередной активизацией и выгрузкой потоков. Переключение осуществляется автоматически планировщиком потоков. Если на компьютере установлено несколько процессоров, планировщик потоков автоматически распределяет потоки между разными процессорами.

При разных запусках программы будут получены разные результаты, поскольку работа планировщика потоков недетерминирована. Более того, вы наверняка увидите значительные различия в результатах работы данной программы-примера, запуская ее на различных версиях пакета JDK. К примеру, предыдущие версии JVM не слишком часто выполняли квантование времени, соответственно, поток 1 мог первым закончить свой цикл, затем все свои итерации произвел бы поток 2, и т. д. Фактически то же самое получилось бы, если бы вызывалась процедура, выполняющая все циклы одновременно, за тем исключением, что запуск совокупности потоков требует больших издержек. Более поздние версии JDK обеспечивают более качественное квантование, и каждый поток регулярно получает свою долю внимания. Как правило, Sun не упоминает о подобных изменениях, так что рассчитывать на определенные «правила поведения» потоков не стоит. Лучше всего при написании кода с потоками занять максимально консервативную позицию.

Поделиться:
Популярные книги

Вкус ледяного поцелуя

Полякова Татьяна Викторовна
2. Ольга Рязанцева
Детективы:
криминальные детективы
9.08
рейтинг книги
Вкус ледяного поцелуя

Проблема майора Багирова

Майер Кристина
1. Спецназ
Любовные романы:
современные любовные романы
6.60
рейтинг книги
Проблема майора Багирова

Прометей: владыка моря

Рави Ивар
5. Прометей
Фантастика:
фэнтези
5.97
рейтинг книги
Прометей: владыка моря

Попаданка в академии драконов 4

Свадьбина Любовь
4. Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
7.47
рейтинг книги
Попаданка в академии драконов 4

(Не)зачёт, Дарья Сергеевна!

Рам Янка
8. Самбисты
Любовные романы:
современные любовные романы
5.00
рейтинг книги
(Не)зачёт, Дарья Сергеевна!

Запасная дочь

Зика Натаэль
Фантастика:
фэнтези
6.40
рейтинг книги
Запасная дочь

Дракон с подарком

Суббота Светлана
3. Королевская академия Драко
Любовные романы:
любовно-фантастические романы
6.62
рейтинг книги
Дракон с подарком

Отвергнутая невеста генерала драконов

Лунёва Мария
5. Генералы драконов
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Отвергнутая невеста генерала драконов

Случайная жена для лорда Дракона

Волконская Оксана
Фантастика:
юмористическая фантастика
попаданцы
5.00
рейтинг книги
Случайная жена для лорда Дракона

Тройняшки не по плану. Идеальный генофонд

Лесневская Вероника
Роковые подмены
Любовные романы:
современные любовные романы
6.80
рейтинг книги
Тройняшки не по плану. Идеальный генофонд

Идеальный мир для Лекаря 28

Сапфир Олег
28. Лекарь
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Идеальный мир для Лекаря 28

Лейтенант космического флота

Борчанинов Геннадий
1. Звезды на погонах
Фантастика:
боевая фантастика
космическая фантастика
космоопера
рпг
фэнтези
фантастика: прочее
5.00
рейтинг книги
Лейтенант космического флота

Гарем на шагоходе. Том 5

Гремлинов Гриша
5. Волк и его волчицы
Фантастика:
боевая фантастика
фэнтези
5.00
рейтинг книги
Гарем на шагоходе. Том 5

Матабар III

Клеванский Кирилл Сергеевич
3. Матабар
Фантастика:
фэнтези
5.00
рейтинг книги
Матабар III