что такое threadgroup и зачем он нужен

Класс Java.lang.ThreadGroup в Java

ThreadGroup создает группу потоков. Он предлагает удобный способ управления группами потоков как единым целым. Это особенно ценно в ситуации, когда вы хотите приостановить и возобновить ряд связанных тем.

Конструкторы:

методы

// Java-код, иллюстрирующий метод activeCount ()

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 1000 ; i++)

catch (InterruptedException ex)

System.out.println( «Exception encounterted» );

public class ThreadGroupDemo

public static void main(String arg[])

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «parent thread group» );

System.out.println( «Starting one» );

System.out.println( «Starting two» );

// проверка количества активных потоков

System.out.println( «number of active thread: «

// Java-код, иллюстрирующий метод activeGroupCount ()

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 1000 ; i++)

catch (InterruptedException ex)

System.out.println( «Exception encounterted» );

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «gfg» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child» );

System.out.println( «Starting one» );

System.out.println( «Starting two» );

// проверка количества активных потоков

System.out.println( «number of active thread group: «

// Java-код, иллюстрирующий метод checkAccess ()

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 1000 ; i++)

catch (InterruptedException ex)

System.out.println( «Exception encounterted» );

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting one» );

System.out.println( «Starting two» );

System.out.println(gfg.getName() + » has access» );

System.out.println(gfg_child.getName() + » has access» );

// Java-код, иллюстрирующий метод destroy ()

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Exception encounterted» );

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting one» );

System.out.println( «Starting two» );

// блокировать, пока не закончится другой поток

// уничтожаем дочерний поток

// уничтожаем родительский поток

// Java-код, иллюстрирующий метод enumerate ().

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex) <

System.out.println( «Exception encounterted» );

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting one» );

System.out.println( «Starting two» );

// возвращает количество потоков, помещенных в массив

Thread[] group = new Thread[gfg.activeCount()];

int count = gfg.enumerate(group);

System.out.println( «Thread » + group[i].getName() + » found» );

// Java-код, иллюстрирующий перечисление (группа Thread [], логический рекурс)

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Exception encounterted» );

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting one» );

System.out.println( «Starting two» );

// возвращает количество потоков, помещенных в массив

Thread[] group = new Thread[gfg.activeCount()];

int count = gfg.enumerate(group, true );

System.out.println( «Thread » + group[i].getName() + » found» );

// Java-код, иллюстрирующий метод enumerate (ThreadGroup [] group)

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Exception encounterted» );

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting one» );

System.out.println( «Starting two» );

// возвращает количество потоков, помещенных в массив

ThreadGroup[] group = new ThreadGroup[gfg.activeCount()];

int count = gfg.enumerate(group);

System.out.println( «ThreadGroup » + group[i].getName() +

// код Java, иллюстрирующий перечисление (группа ThreadGroup [], логическое все)

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Exception encounterted» );

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting one» );

System.out.println( «Starting two» );

// возвращает количество потоков, помещенных в массив

ThreadGroup[] group = new ThreadGroup[gfg.activeCount()];

int count = gfg.enumerate(group, true );

System.out.println( «ThreadGroup » + group[i].getName() +

// Java-код, иллюстрирующий метод getMaxPriority ()

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Exception encounterted» );

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

// проверка максимального приоритета родительского потока

System.out.println( «Maximum priority of ParentThreadGroup = «

System.out.println( «Starting one» );

System.out.println( «Starting two» );

// Java-код, иллюстрирующий метод getName ()

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Exception encounterted» );

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting » + t1.getName());

System.out.println( «Starting » + t2.getName());

// Java-код, иллюстрирующий метод getParent ()

class NewThread extends Thread <

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++) <

catch (InterruptedException ex) <

System.out.println( «Exception encounterted» );

> public class ThreadGroupDemo <

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting » + t1.getName());

System.out.println( «Starting » + t2.getName());

// печатает родительскую ThreadGroup

// как родительских, так и дочерних потоков

System.out.println( «ParentThreadGroup for » + gfg.getName() +

System.out.println( «ParentThreadGroup for » + gfg_child.getName()

// Java-код, иллюстрирующий метод interrupt ()

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Thread » + Thread.currentThread().getName()

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting » + t1.getName());

System.out.println( «Starting » + t2.getName());

// прерывание группы потоков

// Java-код, иллюстрирующий метод isDaemon ()

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Thread » + Thread.currentThread().getName()

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting » + t1.getName());

System.out.println( «Starting » + t2.getName());

if (gfg.isDaemon() == true )

System.out.println( «Group is Daemon group» );

System.out.println( «Group is not Daemon group» );

// Java-код, иллюстрирующий метод isDestroyed ()

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Thread » + Thread.currentThread().getName()

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting » + t1.getName());

System.out.println( «Starting » + t2.getName());

if (gfg.isDestroyed() == true )

System.out.println( «Group is destroyed» );

System.out.println( «Group is not destroyed» );

// Java-код, иллюстрирующий метод list ().

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Thread » + Thread.currentThread().getName()

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting » + t1.getName());

System.out.println( «Starting » + t2.getName());

// выводим содержимое родительской ThreadGroup

System.out.println( «\nListing parentThreadGroup: » + gfg.getName()

// печатает информацию об этой группе потоков

// к стандартному выводу

// Java-код, иллюстрирующий метод parentOf ()

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Thread » + Thread.currentThread().getName()

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting » + t1.getName());

System.out.println( «Starting » + t2.getName());

// проверка, кто является родительским потоком

System.out.println(gfg.getName() + » is parent of » +

// Java-код, иллюстрирующий метод setDaemon ()

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Thread » + Thread.currentThread().getName()

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

// статус демона установлен в true

// статус демона установлен в true

System.out.println( «Starting » + t1.getName());

System.out.println( «Starting » + t2.getName());

if (gfg.isDaemon() && gfg_child.isDaemon())

System.out.println( «Parent Thread group and «

+ «child thread group»

// Java-код, иллюстрирующий метод setMaxPriority ()

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Thread » + Thread.currentThread().getName()

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

System.out.println( «Starting » + t1.getName());

System.out.println( «Starting » + t2.getName());

// Java-код, иллюстрирующий метод toString ()

class NewThread extends Thread

NewThread(String threadname, ThreadGroup tgob)

super (tgob, threadname);

for ( int i = 0 ; i 10 ; i++)

catch (InterruptedException ex)

System.out.println( «Thread » + Thread.currentThread().getName()

public class ThreadGroupDemo

public static void main(String arg[]) throws InterruptedException,

// создаем группу потоков

ThreadGroup gfg = new ThreadGroup( «Parent thread» );

ThreadGroup gfg_child = new ThreadGroup(gfg, «child thread» );

// статус демона установлен в true

// статус демона установлен в true

System.out.println( «Starting » + t1.getName());

System.out.println( «Starting » + t2.getName());

// строковый эквивалент родительской группы

System.out.println( «String equivalent: » + gfg.toString());

Пожалуйста, пишите комментарии, если вы обнаружите что-то неправильное, или вы хотите поделиться дополнительной информацией по обсуждаемой выше теме.

Источник

Волшебный мир Java

воскресенье, 19 февраля 2012 г.

Многопоточность в Java. Часть 1

29 комментариев:

что такое threadgroup и зачем он нужен. Смотреть фото что такое threadgroup и зачем он нужен. Смотреть картинку что такое threadgroup и зачем он нужен. Картинка про что такое threadgroup и зачем он нужен. Фото что такое threadgroup и зачем он нужен

спасбо, прочитал перед сном, ещё раз вспомнил основы.

Не за что. Очень рад, что статья пригодилась.

что такое threadgroup и зачем он нужен. Смотреть фото что такое threadgroup и зачем он нужен. Смотреть картинку что такое threadgroup и зачем он нужен. Картинка про что такое threadgroup и зачем он нужен. Фото что такое threadgroup и зачем он нужен

что такое threadgroup и зачем он нужен. Смотреть фото что такое threadgroup и зачем он нужен. Смотреть картинку что такое threadgroup и зачем он нужен. Картинка про что такое threadgroup и зачем он нужен. Фото что такое threadgroup и зачем он нужен

спасибо, не хватает только про wait и notify рассказать

Рад, что статья помогает.
Постараюсь в ближайшее время написать вторую часть статьи. Все никак руки не доходят. Но постараюсь исправиться 🙂

что такое threadgroup и зачем он нужен. Смотреть фото что такое threadgroup и зачем он нужен. Смотреть картинку что такое threadgroup и зачем он нужен. Картинка про что такое threadgroup и зачем он нужен. Фото что такое threadgroup и зачем он нужен

Недавно начал изучать java. Многопоточность по Эккелю понимается гораздо труднее, а благодаря вашей статье разобрался. Большое спасибо! :))

Очень приятно это слышать. Значит нужно продолжать начатое дело. Постараюсь, более шире раскрыть данную тему.

Изучаю джава по Шилдту 8 издание, не мог норм понять многопотоки, спасибо вам, жду с нетерпением продолжения «синхронизации потоков и пакет concurrent.»

Надеюсь получилось донести мысль сказанного :).

Все понял, спасибо. Есть вопрос о deadlock. Там мне тоже сложно разобраться. В какое приблизительно время вам писать можно, чтоб вы по возможности отвечали, если есть желание помочь. Заранее спасибо.

Deadlock возникает когда поток или потоки переходят в режим ожидания/блокировки и выйти из них не могут. В итоге поток(и) никогда не завершат своей работы. Постараюсь на этих выходных написать статейку по этому поводу. А то все как-то давно собираюсь, да руки не доходят.

В какое время писать, даже не знаю. Иногда бываю днем, иногда вечером, как получается. Если смогу помочь, то с удовольствием помогу

что такое threadgroup и зачем он нужен. Смотреть фото что такое threadgroup и зачем он нужен. Смотреть картинку что такое threadgroup и зачем он нужен. Картинка про что такое threadgroup и зачем он нужен. Фото что такое threadgroup и зачем он нужен

что такое threadgroup и зачем он нужен. Смотреть фото что такое threadgroup и зачем он нужен. Смотреть картинку что такое threadgroup и зачем он нужен. Картинка про что такое threadgroup и зачем он нужен. Фото что такое threadgroup и зачем он нужен

Спасибо, постараюсь писать дальше. Но со временем немного сложновато)

Этот комментарий был удален автором.

что такое threadgroup и зачем он нужен. Смотреть фото что такое threadgroup и зачем он нужен. Смотреть картинку что такое threadgroup и зачем он нужен. Картинка про что такое threadgroup и зачем он нужен. Фото что такое threadgroup и зачем он нужен

доступно написано, спасибо большое автору!

Спасибо за статью, когда будет следующая обещеная Вами статья?)))

Спасибо, было полезно.

что такое threadgroup и зачем он нужен. Смотреть фото что такое threadgroup и зачем он нужен. Смотреть картинку что такое threadgroup и зачем он нужен. Картинка про что такое threadgroup и зачем он нужен. Фото что такое threadgroup и зачем он нужен

Отличная статья для начинающих) Спасибо!

Этот комментарий был удален автором.

Спасибо за статью! Не могу понять почему в последнем примере вывод начинается с результатов работы цикла фор, а не с фразы «Запускаем поток-демон: daemon». Ведь в мейне сперва запускается поток-демон, уже после начинается цикл фор. А в ране потока-демона цикл уайл начинается со строки «Запускаем поток-демон: daemon» и уже после её вывода запускается метод слип. Был бы признателен за пояснение.

что такое threadgroup и зачем он нужен. Смотреть фото что такое threadgroup и зачем он нужен. Смотреть картинку что такое threadgroup и зачем он нужен. Картинка про что такое threadgroup и зачем он нужен. Фото что такое threadgroup и зачем он нужен

что такое threadgroup и зачем он нужен. Смотреть фото что такое threadgroup и зачем он нужен. Смотреть картинку что такое threadgroup и зачем он нужен. Картинка про что такое threadgroup и зачем он нужен. Фото что такое threadgroup и зачем он нужен

что такое threadgroup и зачем он нужен. Смотреть фото что такое threadgroup и зачем он нужен. Смотреть картинку что такое threadgroup и зачем он нужен. Картинка про что такое threadgroup и зачем он нужен. Фото что такое threadgroup и зачем он нужен

Источник

Многопоточность Thread, Runnable

Многопоточное программирование позволяет разделить представление и обработку информации на несколько «легковесных» процессов (light-weight processes), имеющих общий доступ как к методам различных объектов приложения, так и к их полям. Многопоточность незаменима в тех случаях, когда графический интерфейс должен реагировать на действия пользователя при выполнении определенной обработки информации. Потоки могут взаимодействовать друг с другом через основной «родительский» поток, из которого они стартованы.

В качестве примера можно привести некоторый поток, отвечающий за представление информации в интерфейсе, который ожидает завершения работы другого потока, загружающего файл, и одновременно отображает некоторую анимацию или обновляет прогресс-бар. Кроме того этот поток может остановить загружающий файл поток при нажатии кнопки «Отмена».

Преимущества потоков перед процессами

Главный поток

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

Класс Thread

В классе Thread определены семь перегруженных конструкторов, большое количество методов, предназначенных для работы с потоками, и три константы (приоритеты выполнения потока).

Конструкторы класса Thread

Пример создания потока, который входит в группу, реализует интерфейс Runnable и имеет свое уникальное название :

Группы потоков удобно использовать, когда необходимо одинаково управлять несколькими потоками. Например, несколько потоков выводят данные на печать и необходимо прервать печать всех документов поставленных в очередь. В этом случае удобно применить команду ко всем потокам одновременно, а не к каждому потоку отдельно. Но это можно сделать, если потоки отнесены к одной группе.

Несмотря на то, что главный поток создаётся автоматически, им можно управлять. Для этого необходимо создать объект класса Thread вызовом метода currentThread().

Методы класса Thread

Наиболее часто используемые методы класса Thread для управления потоками :

Жизненный цикл потока

При выполнении программы объект Thread может находиться в одном из четырех основных состояний: «новый», «работоспособный», «неработоспособный» и «пассивный». При создании потока он получает состояние «новый» (NEW) и не выполняется. Для перевода потока из состояния «новый» в «работоспособный» (RUNNABLE) следует выполнить метод start(), вызывающий метод run().

Поток может находиться в одном из состояний, соответствующих элементам статически вложенного перечисления Thread.State :

NEW — поток создан, но еще не запущен;
RUNNABLE — поток выполняется;
BLOCKED — поток блокирован;
WAITING — поток ждет окончания работы другого потока;
TIMED_WAITING — поток некоторое время ждет окончания другого потока;
TERMINATED — поток завершен.

Пример использования Thread

В примере ChickenEgg рассматривается параллельная работа двух потоков (главный поток и поток Egg), в которых идет спор, «что было раньше, яйцо или курица?». Каждый поток высказывает свое мнение после небольшой задержки, формируемой методом ChickenEgg.getTimeSleep(). Побеждает тот поток, который последним говорит свое слово.

При выполнении программы в консоль было выведено следующее сообщение.

Невозможно точно предсказать, какой поток закончит высказываться последним. При следующем запуске «победитель» может измениться. Это происходит вследствии так называемого «асинхронного выполнения кода». Асинхронность обеспечивает независимость выполнения потоков. Или, другими словами, параллельные потоки независимы друг от друга, за исключением случаев, когда бизнес-логика зависимости выполнения потоков определяется предусмотренными для этого средств языка.

Интерфейс Runnable

Интерфейс Runnable содержит только один метод run() :

Метод run() выполняется при запуске потока. После определения объекта Runnable он передается в один из конструкторов класса Thread.

Пример класса RunnableExample, реализующего интерфейс Runnable

При выполнении программы в консоль было выведено следующее сообщение.

Синхронизация потоков, synchronized

В процессе функционирования потоки часто используют общие ресурсы приложения, определенные вне потока. Если несколько потоков начнут одновременно вносить изменения в общий ресурс, то результаты выполнения программы могут быть непредсказуемыми. Рассмотрим следующий пример :

В примере определен общий ресурс в виде класса CommonObject, в котором имеется целочисленное поле counter. Данный ресурс используется внутренним классом, создающим поток CounterThread для увеличения в цикле значения counter на единицу. При старте потока полю counter присваивается значение 1. После завершения работы потока значение res.counter должно быть равно 4.

Две строчки кода класса CounterThread закомментированы. О них речь пойдет ниже.

В главном классе программы SynchronizedThread.main запускается пять потоков. То есть, каждый поток должен в цикле увеличить значение res.counter с единицы до четырех; и так пять раз. Но результат работы программы, отображаемый в консоли, будет иным :

То есть, с общим ресурсов res.counter работают все потоки одновременно, поочередно изменяя значение.

Чтобы избежать подобной ситуации, потоки необходимо синхронизировать. Одним из способов синхронизации потоков связан с использованием ключевого слова synchronized. Оператор synchronized позволяет определить блок кода или метод, который должен быть доступен только одному потоку. Можно использовать synchronized в своих классах определяя синхронизированные методы или блоки. Но нельзя использовать synchronized в переменных или атрибутах в определении класса.

Блокировка на уровне объекта

Блокировать общий ресурс можно на уровне объекта, но нельзя использовать для этих целей примитивные типы. В примере следует удалить строчные комментарии в классе CounterThread, после чего общий ресурс будет блокироваться как только его захватит один из потоков; остальные потоки будут ждать в очереди освобождения ресурса. Результат работы программы при синхронизации доступа к общему ресурсу резко изменится :

Следующий код демонстрирует порядок использования оператора synchronized для блокирования доступа к объекту.

Блокировка на уровне метода и класса

Блокировать доступ к ресурсам можно на уровне метода и класса. Следующий код показывает, что если во время выполнения программы имеется несколько экземпляров класса DemoClass, то только один поток может выполнить метод demoMethod(), для других потоков доступ к методу будет заблокирован. Это необходимо когда требуется сделать определенные ресурсы потокобезопасными.

Каждый объект в Java имеет ассоциированный с ним монитор, который представляет своего рода инструмент для управления доступа к объекту. Когда выполнение кода доходит до оператора synchronized, монитор объекта блокируется, предоставляя монопольный доступ к блоку кода только одному потоку, который произвел блокировку. После окончания работы блока кода, монитор объекта освобождается и он становится доступным для других потоков.

Некоторые важные замечания использования synchronized

Примечание : для синхронизации потоков можно использовать объекты синхронизации Synchroniser’s пакета java.util.concurrent.

Взаимная блокировка

С использованием блокировок необходимо быть очень внимательным, чтобы не создать «взаимоблокировку», которая хорошо известна разработчикам. Этот термин означает, что один из потоков ждет от другого освобождения заблокированного им ресурса, в то время как сам также заблокировал один из ресурсов, доступа к которому ждёт второй поток. В данном процессе могут участвовать два и более потоков.

Основные условия возникновения взаимоблокировок в многопотоковом приложении :

Взаимодействие между потоками в Java, wait и notify

При взаимодействии потоков часто возникает необходимость приостановки одних потоков и их последующего извещения о завершении определенных действий в других потоков. Так например, действия первого потока зависят от результата действий второго потока, и надо каким-то образом известить первый поток, что второй поток произвел/завершил определенную работу. Для подобных ситуаций используются методы :

Все эти методы вызываются только из синхронизированного контекста (синхронизированного блока или метода).

Рассмотрим пример «Производитель-Склад-Потребитель» (Producer-Store-Consumer). Пока производитель не поставит на склад продукт, потребитель не может его забрать. Допустим производитель должен поставить 5 единиц определенного товара. Соответственно потребитель должен весь товар получить. Но, при этом, одновременно на складе может находиться не более 3 единиц товара. При реализации данного примера используем методы wait() и notify().

Листинг класса Store

Класс Store содержит два синхронизированных метода для получения товара get() и для добавления товара put(). При получении товара выполняется проверка счетчика counter. Если на складе товара нет, то есть counter

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *