В Java SE5 появилась новая версия sleep(), оформленная в виде метода класса Timellnit; она продемонстрирована в приведенном примере. Она делает программу более наглядной, поскольку вы можете указать единицы измерения продолжительности задержки. Класс Timellnit также может использоваться для выполнения преобразований, как будет показано далее в этой главе.
На некоторых платформах задачи выполняются в порядке «идеального распределения» — от 0 до 4, затем снова от 4 до 0. Это вполне логично, поскольку после каждой команды вывода задача переходит в состояние ожидания, что позволяет планировщику потоков переключиться на другой поток. Тем не менее такое поведение зависит от базовой реализации потокового механизма, поэтому полагаться на него нельзя. Если вам потребуется управлять порядком выполнения задач, используйте средства синхронизации (см. далее) или же вообще откажитесь от использования потоков и напишите собственные функции синхронизации, которые передают управление друг другу в нужном порядке.
Приоритет
Приоритет (priority) потока сообщает планировщику информацию об относительной важности потока. Хотя порядок обращения процессора к существующему набору потоков и не детерминирован, если существует несколько приостановленных потоков, одновременно ожидающих запуска, планировщик сначала запустит поток с большим приоритетом. Впрочем, это не значит, что потоки с младшими приоритетами не выполняются вовсе (то есть тупиковых ситуаций из-за приоритетов не возникает). Потоки с более низкими приоритетами просто запускаются чуть реже.
В подавляющем большинстве случаев все потоки должны выполняться со стандартным приоритетом. Любые попытки манипуляций с приоритетами обычно являются ошибкой.
Следующий пример демонстрирует использование приоритетов. Приоритет существующего потока читается методом getPriority() и задается методом setPriority():
//• concurrency/Si mplePri ori ti es.java
// Использование приоритетов потоков.
import java.util.concurrent.*.
public class SimplePriorities implements Runnable { private int countDown = 5;
private volatile double d; // Без оптимизации продолжение &
private int priority; public SimplePriorities(int priority) { this.priority = priority;
}
public String toStringO {
return Thread.currentThreadО + "; " + countDown;
}
public void runО {
Thread.currentThreadO.setPriority(priority); while(true) {
// Высокозатратная, прерываемая операция; for(int 1=1: i < 100000; i++) {
d += (Math.PI + Math.E) / (double)i; ifCi % 1000 == 0)
Thread.yieldO;
}
System.out.printin(this); if(--countDown == 0) return;
}
}
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPoolО; for(int i = 0; i < 5; i++) exec.execute(
new SimplePriorities(Thread.MIN_PRIORITY));
exec.execute(
new SimplePriorities(Thread.MAX_PRIORITY)); exec.shutdownO;
}
} /* Output:
Thread[pool-l-thread-6.10.main]: 5 ThreadEpool-l-thread-6.10.main]: 4 ThreadEpool-l-thread-6.10.main]: 3 ThreadEpool-l-thread-6.10.main]: 2 ThreadEpool-l-thread-6.10.main]: 1 ThreadEpool-l-thread-3.1.main]: 5 ThreadEpool-l-thread-2.1.main]: 5 ThreadEpool-1-thread-l.1.main]: 5 ThreadEpool-l-thread-5.1.main]: 5 ThreadEpool-l-thread-4.1.main]: 5