Метод Thread.Sleep()
Thread.sleep() — статический метод класса Thread, который приостанавливает выполнение потока, в котором он был вызван. Во время выполнения метода sleep() система перестает выделять потоку процессорное время, распределяя его между другими потоками. Метод sleep() может выполняться либо заданное кол-во времени (миллисекунды или наносекунды) либо до тех пор пока он не будет остановлен прерыванием (в этом случае он сгенерирует исключение InterruptedException). Thread.sleep(1500); //Ждет полторы секунды
Thread.sleep(2000, 100); //Ждет 2 секунды и 100 наносекунд
Метод yield()
Статический метод Thread.yield() заставляет процессор переключиться на обработку других потоков системы. Метод может быть полезным, например, когда поток ожидает наступления какого-либо события и необходимо чтобы проверка его наступления происходила как можно чаще. В этом случае можно поместить проверку события и метод Thread.yield() в цикл:
//Ожидание поступления сообщения
while(!msgQueue.hasMessages()) //Пока в очереди нет сообщений
{
Thread.yield(); //Передать управление другим потокам
}
Метод join()
В Java предусмотрен механизм, позволяющий одному потоку ждать завершения выполнения другого. Для этого используется метод join(). Например, чтобы главный поток подождал завершения побочного потока myThready, необходимо выполнить инструкцию myThready.join() в главном потоке. Как только поток myThready завершится, метод join() вернет управление, и главный поток сможет продолжить выполнение. Метод join() имеет перегруженную версию, которая получает в качестве параметра время ожидания. В этом случае join() возвращает управление либо когда завершится ожидаемый поток, либо когда закончится время ожидания. Подобно методу Thread.sleep() метод join может ждать в течение миллисекунд и наносекунд – аргументы те же.
Многопоточность: синхронизация потоков (synchronize), согласование работы потоков. Модель потребитель-поставщик.
Процессы и потоки, работающие одновременно в многопоточной системе, могут пытаться обращаться одновременно к одним и тем же ресурсам, что может привести к неправильной работе приложений.
Синхронизация методов
Возможность синхронизации как бы встроена в каждый объект, создаваемый приложением Java. Для этого объекты снабжаются защелками, которые могут быть использованы для блокировки потоков, обращающихся к этим объектам.
Чтобы воспользоваться защелками, вы можете объявить соответствующий метод как synchronized, сделав его синхронизированным:
public synchronized void decrement()
{
. . .
}
При вызове синхронизированного метода соответствующий ему объект (в котором он определен) блокируется для использования другими синхронизированными методами. В результате предотвращается одновременная запись двумя методами значений в область памяти, принадлежащую данному объекту.
Использование синхронизированных методов - достаточно простой способ синхронизации потоков, обращающихся к общим критическим ресурсам
Заметим, что не обязательно синхронизовать весь метод - можно выполнить синхронизацию только критичного фрагмента кода.
Согласование работы нескольких потоков
Возможность создания многопоточных программ заложена в язык Java с самого его создания. В каждом объекте есть три метода wait() и один метод notify(), позволяющие приостановить работу потока с этим объектом, позволить другому потоку поработать с объектом, а затем уведомить (notify) первый поток о возможности продолжения работы. Эти методы определены прямо в классе Object и наследуются всеми классами.
С каждым объектом связано множество потоков, ожидающих доступа к объекту (wait set). Вначале этот "зал ожидания" пуст.
Основной метод wait(long millisec) приостанавливает текущий поток this, работающий с объектом, на millisec миллисекунд и переводит его в "зал ожидания", в множество ожидающих потоков. Обращение к этому методу допускается только в синхронизированном блоке или методе, чтобы быть уверенными в том, что с объектом работает только один поток. По истечении millisec или после того, как объект получит уведомление методом notify(), поток готов возобновить работу. Если аргумент millisec равен 0, то время ожидания не определено и возобновление работы потока возможно только после того, как объект получит уведомление методом notify().
Отличие данного метода от метода sleep() в том, что метод wait() снимает блокировку с объекта. С объектом может работать один из потоков из "зала ожидания", обычно тот, который ждал дольше всех, хотя это не гарантируется спецификацией JLS.
Второй метод wait() эквивалентен wait(0). Третий метод wait (long millisec, int nanosec) уточняет задержку на nanosec наносекунд, если их сумеет отсчитать операционная система.
Метод notify() выводит из "зала ожидания" только один, произвольно выбранный поток. Метод notifyAll() выводит из состояния ожидания все потоки. Эти методы тоже должны выполняться в синхронизированном блоке или методе.
Многопоточность: приоритеты потоков, группы потоков, обработка неперехваченных исключений
