Главная » Java » Принудительное переупорядочение Java

0

в составе класса Thread есть несколько методов, которые позволяют потоку уменьшить его потребность в ресурсе процессорного времени. В соответствии с принятым соглашением, статические методы класса Thread всегда применяются по отношению к текущему работающему потоку; поскольку другой поток не может выполнить явный захват ресурсов,’ все методы принудительного переупорядочения потоков объявлены как статические.

public static void sleep(long millis) throws InterruptedException Вынуждает текущий работающий поток приостановить выполнение ("уснуть") на период времени, не меньший заданного (время указывается В миллисекундах). Точность промежутка времени приостановки не гарантируется из-за возможного влияния расписания работы других ПОТОКОВ, погрешностей дискретизации системного таймера и иных факторов. Если Во время "спячки" вызывается метод intеrrupt, выбрасывается исключение типа InterruptedException.

public static void sleep(long millis, int nanos)

throws InterruptedException

Вынуждает текущий работающий поток "уснуть" на период времени, не меньший заданного (время указывается в миллисекундах и наносекундах). Величина nanos должна находиться в промежутке 0-999999.

public static void yield();

Сообщает планировщику заданий, что текущий поток в данный момент можно не выполнять и вычислительные ресурсы при необходимости следует передать другому потоку. Планировщик вправе последовать этому совету или оставить его без внимания – вообще говоря, нам остается верить в то, что планировщик "поступает правильно", хотя строгих спецификаций этого процесса не существует.

Следующий при мер иллюстрирует возможность воздействия на расписание работы потоков с помощью метода уiеld. Программа принимает в качестве параметров командной строки список слов и создает отдельные потоки, ответственные за вывод на экран каждого из них. Первый параметр указывает, следует ли потоку после очередного вызова println выполнять обращение к методу уiеld второй задает количество повторений каждого слова на экране; все остальные параметры – это слова, подлежащие обработке.

class Babble extends Thread {

       static boolean doYield;                // выполнять ли вызов yield?

       static int howoften;                      // Количество повторений слова

на экране

private String word;                            // Слово, подлежащее обработке

Babble(String whatToSay) { word = whatToSay;

}

public void run() {

for (int i = о; i < howoften; i++) {

 System.out.println(word);

if (doYield)

Thread.yield(); // предоставить ресурсы другим потокам

                }

}

public static void main(String[] args) {

doYield = new Boolean(args[0]).booleanValue();

 howoften = Integer.parseInt(args[l]);

// создать потоки для обработки каждого слова

for (int i = 2; i < args.length; i++)

new Babble(args[i]).start();

                }

}

Когда вызов уiеld не предусмотрен, каждый поток захватывает продолжительные "куски" процессорного времени, выполняя собственную работу до конца и не позволяя другим потокам "вклиниться" в процесс. Предположим, что программа запущена на выполнение таким образом, чтобы полю doYield было присвоено значение false:

Babble false 2 Быть Не_Быть

Результат работы программы в этом случае, вероятнее всего, будет выглядеть так:

Быть

Быть

Не_Быть

Не_Быть

Если каждый поток после выполнения println обращается к уiеld, возможность работы предоставляется и другим потокам. Предположим, что теперь программа запускается следующим образом:

Babble true 2 Быть Не_Быть

Вызов уiеld объекта одного потока дает шанс "отличиться" другим потокам, а те, в свою очередь, также обращаются к уiеld, и в итоге может получиться нечто подобное:

Быть

Не_Быть

Не_Быть

Быть

Показанный текст можно рассматривать только как пример – вы, вероятно, ожидали, что слова будут чередоваться? Другая реализация потока способна привести к иным результатам, или одна и та же реализация может давать неодинаковые результаты в различных сеансах работы приложения. Но в любой Ситуации применение уiеld означает, что система приостанавливает работу текущего потока и предоставляет ресурсы другим потокам.

Существуют два других фактора, оказывающих влияние на поведение этой программы (и всех других подобных программ, которые можно написать для демонстрации особенностей упорядочения потоков во времени). Первый связан с Тем, что метод println сам по себе использует механизм синхронизации, и всем Потокам приходится оспаривать право на владение одной и той же блокировкой. Теперь о втором факторе _ в нашей программе "живут", на самом деле, три потока,  а не два, как может показаться на первый взгляд. Поток метода main ответствен за создание и запуск на выполнение двух потоков Babble, а это означает, что он также состязается за ресурс процессорного времени. Вполне возможно, ‘ITO первый поток Babble успеет завершиться полностью даже раньше, чем потоку таin будет предоставлен малейший шанс создать и запустить на выполнение второй поток Babble.

 

Упражнение 10.7. Запустите программу Babble несколько раз и про верьте результаты – всегда ли они одинаковы? Если возможно, протестируйте программу в различных системах и сопоставьте итоги.

Источник: Арнолд, Кен, Гослинг, Джеймс, Холмс, Дэвид. Язык программирования Java. 3-е изд .. : Пер. с англ. – М. : Издательский дом «Вильяме», 2001. – 624 с. : ил. – Парал. тит. англ.

По теме:

  • Комментарии