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

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

Жанры

Философия 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 не упоминает о подобных изменениях, так что рассчитывать на определенные «правила поведения» потоков не стоит. Лучше всего при написании кода с потоками занять максимально консервативную позицию.

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

Зодчий. Книга V

Погуляй Юрий Александрович
5. Зодчий Империи
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Зодчий. Книга V

Брак по-драконьи

Ардова Алиса
Фантастика:
фэнтези
8.60
рейтинг книги
Брак по-драконьи

Викинг

Мазин Александр Владимирович
1. Викинг
Приключения:
исторические приключения
8.92
рейтинг книги
Викинг

Тихие ночи

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

Мастер Трав III

Мордорский Ваня
3. Мастер Трав
Фантастика:
фэнтези
рпг
фантастика: прочее
попаданцы
5.75
рейтинг книги
Мастер Трав III

Третье правило диверсанта

Бычков Михаил Владимирович
Фантастика:
постапокалипсис
5.67
рейтинг книги
Третье правило диверсанта

Товарищ «Чума» 8

lanpirot
8. Товарищ "Чума"
Фантастика:
городское фэнтези
попаданцы
альтернативная история
5.00
рейтинг книги
Товарищ «Чума» 8

Кодекс Охотника. Книга XV

Винокуров Юрий
15. Кодекс Охотника
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XV

Волкодав

Семёнова Мария Васильевна
1. Волкодав
Фантастика:
фэнтези
героическая фантастика
9.46
рейтинг книги
Волкодав

Технарь

Муравьёв Константин Николаевич
1. Технарь
Фантастика:
космическая фантастика
попаданцы
7.13
рейтинг книги
Технарь

Черный Маг Императора 19

Герда Александр
19. Черный маг императора
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Черный Маг Императора 19

Геном хищника. Книга шестая

Гарцевич Евгений Александрович
6. Я - Легенда!
Старинная литература:
прочая старинная литература
5.00
рейтинг книги
Геном хищника. Книга шестая

Эпоха Опустошителя. Том V

Павлов Вел
5. Вечное Ристалище
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Эпоха Опустошителя. Том V

Цеховик. Книга 1. Отрицание

Ромов Дмитрий
1. Цеховик
Фантастика:
попаданцы
альтернативная история
5.75
рейтинг книги
Цеховик. Книга 1. Отрицание