В этой статье в основном изучаются пример приложения кода условия блокировки параллелизма Java, следующим образом.
Условие разбивает методы монитора объекта (подождите, уведомляйте и уведомляют) на совершенно разные объекты, чтобы, объединив эти объекты с любой реализацией блокировки, каждый объект предоставляет несколько наборов ожидания (набор ожидания). Среди них Lock заменяет использование синхронизированных методов и операторов, а условие заменяет использование методов монитора объектов.
Поскольку условие можно использовать для замены ожидания, уведомления и других методов, мы можем сравнить код межпоточной связи, написанный ранее, и взглянуть на исходную проблему:
Есть две темы. Сначала работа дочернего поток выполняется 10 раз, затем основной поток выполняется 5 раз, а затем переключается на детскую потоку, выполняющую 10, а затем основной поток выполняется 5 раз ... эта обработка в рамках обработки в 50 раз.
Я использовал ждать и уведомлять, чтобы реализовать его раньше, но теперь я использую условие для переписывания его, код выглядит следующим образом:
Public Class Conditionmunication {public static void main (string [] args) {business business = new Business (); new Thread (new Runnable () {// открыть детскую нить @Override public void run () {for (int i = 1; i <= 50; i ++) {bussiness.sub (i);}}}). 50; {condity.await (); // Использовать условие для вызова метода await} catch (exception e) {// todo автоматически сгенерированное catch blocke.printstacktrace ();}} для (int j = 1; j <= 10; j ++) {System.out.println («Последовательность подразделения» + j + », loop of a); false; condity.Signal (); // Использовать условие для отправки сигнала пробуждения и разбудить определенный}}, наконец, {lock.unlock ();}} public void main (int i) {lock.lock (); try {while (bshouldsub) {try {condition.await (); // Условие Calm wait} ekember e). blocke.printstacktrace ();}} for (int j = 1; j <= 10; j ++) {System.out.println («Основная последовательность потока" + j + ", петля" + i);} bshouldsub = true; condition.signal (); // Условие использования, чтобы отправить сигнал пробуждения, пробудить определенное один один} {lock.С точки зрения кода условие используется вместе с блокировкой. Без блокировки условие нельзя использовать, потому что условие создается через блокировку. Это использование очень просто. Пока вы освоите использование синхронизации, подождите и уведомите, вы можете полностью освоить использование блокировки и условия.
Выше использует блокировку и состояние вместо синхронизированных и методов монитора объектов для реализации связи между двумя потоками. Теперь давайте напишем немного более продвинутое приложение: моделируйте очередь блокировки буфера.
Что такое буфер? Например, есть много людей, которые хотят отправлять сообщения сейчас. Я транзитная станция и хочу помочь другим отправлять сообщения. Так что теперь мне нужно сделать две вещи. Одна вещь, чтобы получить сообщения, отправленные пользователем, и поместить их в буфер в порядке. Другое дело, чтобы взять сообщения, отправленные пользователем в порядок из буфера, и отправить их.
Теперь абстрактно эта фактическая проблема: буфер - это массив. Мы можем записать данные в массив или взять данные из массива. Две вещи, которые мне нужно сделать, - это запустить два потока, одна для хранения данных, а другая, чтобы получить данные. Но проблема в том, что если буфер заполнен, это означает, что полученное слишком много сообщений, то есть отправленное сообщение слишком быстрое, а другой поток моей жизни недостаточно, чтобы отправить его, что приводит к тому, что буфер не остается в курсе, поэтому поток хранилища данных должен быть заблокирован и дать ему ждать; Напротив, если я пересылаю его слишком быстро, и теперь все содержимое буфера было отправлено мной, и пользователь не отправит новые сообщения, тогда в настоящее время поток сбора данных должен быть заблокирован.
Хорошо, после анализа очереди блокировки этого буфера, давайте использовать технологию условий для его реализации:
Buffer Class {final Lock Lock = new ReentrantLock (); // Определить конечное условие блокировки. count; // Абоненты массивы используются для калибровки данных положения // хранилища в очередь public void put (объект x) броски прерванного Быть! »); natufull.await (); // Если очередь полна, то заблокируйте поток хранения данных, ожидая, чтобы разбудить} // Если она не полна, храните элементы [putptr] = x; if (++ putptr == items.length) // Это решение, которое достигает конца массива. Если это достигнуто, вернитесь к началу putptr = 0; ++ count; // количество сообщений System.out.println (think.currentThread (). GetName () + «Сохранить значение:» + x); notempty.Signal (); // ОК, теперь есть данные. Разбудите поток пустой очередью, и вы можете получить данные}, наконец, {lock.unlock (); // Загрузить Lock}} // Извлекать данные из queue public object ablet () throws retruptedException {lock.lock (); // lock try {while (count == 0) {system.out.println (thread.currentthread (). Быть! "); notempty.await (); // Если очередь пуста, то поток блокирует данные, чтобы получить поток, ожидая, чтобы разбудить} // Если он не пуст, возьмите объект x = элементы [tableptr]; if (++ tableptr == elects.length) // Судите, достигает ли он конец, если он вернется, вернется к началу takept System.out.println (think.currentThread (). GetName () + "Уберите значение:" + x); natufull.Signal (); // Хорошо, теперь в очереди есть место. Разбудите поток, полную очереди, и вы можете хранить данные. Return x;} наконец {lock.unlock (); // lock}}}Эта программа классическая, я вытащил ее из официальной документации JDK и добавил комментарии. В программе определены два условия, которые используются для выполнения двух потоков, а также ожидают и просыпаются соответственно. Идея ясна, и программа также очень надежная. Один вопрос можно рассмотреть, зачем вам использовать два кода? Там должна быть причина для этого дизайна. Если вы используете условие, теперь предположим, что очередь заполнена, но есть 2 потока A и B, которые хранят данные одновременно, то все они входят в сон. Хорошо, теперь другая поток забирает один, а затем просыпается одна из потоков А, а затем а может спасти его. После сохранения разбудится еще одна ветка. Если B пробуждается, возникнет проблема, потому что очередь полна в настоящее время, и B не может хранить ее. Если B хранит, это будет перезаписать значение, которое не было извлечено. Поскольку используется состояние, как хранение, так и снятие средств используют это состояние для сна и проснуться, и оно будет испорчено. На этом этапе вы можете понять использование этого условия. Теперь давайте проверим эффект блокирующей очереди выше:
Общедоступный Class Buffer Buffer {public static void main (string [] args) {buffer buffer = new Buffer (); for (int i = 0; i <5; i ++) {// Открыть 5 потоков для хранения данных в новом буфере (new Runnable () {@Override public run () {try {buffer.pute (new random (). (Прерывание Exception e) {e.printstacktrace ();}}}). Start ();} для (int i = 0; i <10; i ++) {// Открыть 10 потоков, чтобы получить данные из буфера нового потока (new Runnable () {@override public run () {try {buffer.take ();//@@override public run () {try {buffer.take ();//@@override public run run () {try {buffer.take (); {e.printstacktrace ();}}}). start ();}}}}Я намеренно включил только 5 потоков для хранения данных и 10 потоков для получения данных, просто чтобы они заблокировали от получения данных, и увидеть результаты операции:
Thread-5 заблокирована, и данные не могут быть извлечены на данный момент!
Thread-10 блокируется, и данные не могут быть извлечены на данный момент!
Сохраненное значение Thread-1: 755
Поток-0 Сохраненное значение: 206
Сохраняемое значение 2-й теме 2: 741
Поток-3 Сохраняемое значение: 381
Устраненое значение Thread-14: 755
Поток-4 Сохраняемое значение: 783
Thread-6 Уберите значение: 206
Поток-7 Удаленное значение: 741
Поток-8 Удаленное значение: 381
Thread-9 Уберите значение: 783
Thread-5 заблокирована, и данные не могут быть извлечены на данный момент!
Thread-11 блокируется, и данные не могут быть извлечены на данный момент!
Поток-12 блокируется, и данные не могут быть извлечены на данный момент!
Thread-10 блокируется, и данные не могут быть извлечены на данный момент!
Поток-13 заблокирован, и данные не могут быть извлечены на данный момент!
Из результатов мы видим, что потоки 5 и 10 выполняются первыми, и они обнаруживают, что в очереди нет, поэтому они заблокированы и спит там. Они могут получить его только до тех пор, пока в очереди не будет сохранено новое значение. Тем не менее, им не повезло, и сохраненные данные взяты в первую очередь другими потоками. Ха -ха ... они могут запустить его еще несколько раз. Если вы хотите, чтобы хранимых данных заблокированы, вы можете установить поток, чтобы принести данные немного меньше, и я не буду установить их здесь.
Это все же вопрос, что и раньше. Теперь пусть три потока выполнит его. Давайте посмотрим на вопрос:
Существует три потока, дочерний поток 1 выполняет 10 раз сначала, ребенок 2 выполняется 10 раз, затем основной поток выполняется 5 раз, затем переключайте на ребенка поток 1, выполняющий 10 раз, ребенок 2, поток 2 выполняется 10 раз, главный поток выполняется 5 раз ... эта переход в рамках раздачи в 50 раз.
Если вы не используете состояние, это действительно сложно сделать, но это очень удобно сделать это с условием. Принцип очень прост. Определите три условия. После того, как дочерняя резьба 1 выполняет, дочерняя нить 2 просыпается в основной резьбе, а основная нить разбудит дочернюю резьбу 1. Механизм пробуждения похож на буфер выше. Давайте посмотрим на код ниже, это легко понять.
открытый класс ThreeConditionCommunication {public static void main (string [] args) {business business = new Business (); new Thread (new Runnable () {// Открыть детскую нить @Override public void run () {for (int i = 1; i <= 50; i ++) {busses.sub1 (i);}}}). newsemanse); {// запустить другую детскую поток @override public void run () {for (int i = 1; i <= 50; i ++) {bussiness.sub2 (i);}}}). Start (); // Основной метод основной метод для (int i = 1; i <= 50; i ++) {bussense.main (i);}} static class class strasclock {static strasclock {entlocklock {etcrasclish {{i); Condition1 = lock.newCondition (); // Условие - это условие 2 = lock.newCondition (); условие условия = lock.newCondition (); private int bshouldsub = 0; public void sub1 (int i) {lock.lock (); try {while (bshouldsub! {// todo автоматически сгенерированный лоткой blocke.printstacktrace ();}} for (int j = 1; j <= 10; j ++) {System.out.println ("Последовательность потока подзадна" + j + ", Loop of" + i);} bshouldsub = 1; condition2.signal (); // alte execute} {lock.unlock ();}} public void sub2 (int i) {lock.lock (); try {while (bshouldsub! = 1) {try {condition2.await (); // Использовать условие, чтобы вызвать метод await} catch (Exception e) {// todo Auto-Generated Catchcke.printStacktrace (); in (in j = 1; j ++) {System.out.println ("Последовательность потока Sub2" + j + ", цикл" + i);} bshouldsub = 2; conditionmain.signal (); // позволить основной потоке выполнить} наконец {lock.unlock ();}} public void main (int i) {lock.lock.lock () tress {bsh (bsh); {condityMain.await (); // Использовать условие для вызова метода await} catch (Exception e) {// todo автоматически сгенерированный слой blocke.printstacktrace ();}} для (int j = 1; j <= 5; j ++) {System.out.println («Основная последовательность поток» + j + », loop of aT.t.t.t.println (« Основная нить »); 0; condity1.signal (); // Пусть потока 1 выполнить} наконец {lock.unlock ();}}}}Код кажется немного длинным, но это иллюзия, и логика очень проста. Это все для суммирования технологии состояния в потоках.
Выше приведено все содержание этой статьи о примере кода приложения условия блокировки параллелизма Java. Я надеюсь, что это будет полезно для всех. Заинтересованные друзья могут продолжать ссылаться на другие связанные темы на этом сайте. Если есть какие -либо недостатки, пожалуйста, оставьте сообщение, чтобы указать это. Спасибо, друзья, за вашу поддержку на этом сайте!