Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lab12_Java_Vkazivky_2010_Multithreading.doc
Скачиваний:
7
Добавлен:
17.04.2019
Размер:
921.6 Кб
Скачать

17.4. Узгодження роботи декількох підпроцесів

Можливість створення багатопотокових програм закладена в Java з самого її створення. В кожному обєкті єсть три методи wait() і один метод notify(), дозволяючі призупиняти роботу підпроцесу з цим обєктом, дозволити іншому підпроцесу попрацювати з обєктом, а потім сповістити (notify) перший підпроцес про можливість продовження роботи. Ці методи визначені прямо в класі object і наслідуються всіма класами. З кожним обєктом звязано багато підпроцесів, очікуючих доступу до обєкту (wait set). Спочатку цей "зал очікування" порожній.

Основний метод wait (long miІІisec) призупиняє поточний підпроцес this, працюючий з обєктом, на miІІisec мілісекунд і переводить його в "зал очікування", в множину очікуючих підпроцесів. Звернення до цього методу допускається тільки в синхронізованому блоці або методі, щоб бути впевненими в тому, що з обєктом працює тільки один підпроцес. Через miІІisec або після того, як обєкт отримає сповіщення методом notify(), підпроцес готовий відновити роботу. Якщо аргумент miІІisec рівний 0, то час очікування не визначено і відновлення роботи підпроцесу можна тільки після того, як обєкт отримає сповіщення методом notify(). Відміна даного методу від методу sleep() в тому, що метод wait() знімають блокування з обєкта. З обєктом може працювати один із підпроцесів із "зала очікування", звичайно той, який чекав довше всіх, хоч це не гарантуеться специфікацією JLS.

Другий метод wait () еквівалентний wait(0). Третій метод wait (long millisec, int nanosec) уточнює затримку на nanosec наносекунд, якщо їх зуміє відрахувати операційна система. Метод notify() виводить із "зали очікування" тільки один, довільно вибраний підпроцес. Метод notifyAll() виводить із стану очікування всі підпроцеси. Ці методи теж повинні виконуватися в синхронізованому блоці або методі. Як же застосувати все це для узгодженого доступу до обєкта? Як завжди, краще всього пояснити це на прикладі.

Звернемося знову до схеми "постачальик-споживач", уже використану в уроці 15. Один підпроцес, постачальник, робить обчислення, другий, споживач, очікує результати цих обчислень і використовує їх в міру поступання. Підпроцеси передають інформацію через спільний екземпляр st класу store. Робота цих підпроцесів повинна бути узгоджена. Споживач зобовязаний чекати, доки постачальник не занесе результат обчислення в обєкт st, а постачальник повинен чекати, доки споживач не візьме цей результат. Для простоти постачальник просто заносить в спільний обєкт класу store цілі числа, а споживач лише забирає їх. В лістинзі 17.6 клас store не забезпечує узгодженості отримання і видачі інформацію. Результат роботи показаний на рис. 17.4.

Лістинг 17.6. Неузгоджені підпроцеси

class Store{

private inf inform;

synchronized public int getlnform(){ return inform; }

synchronized public void setlnform(int n){ inform = n; }

}

class Producer implements Runnable{

private Store st;

private Thread go;

Producer(Store st){

this.st = st;

go = new Thread(this);

go.start();

}

public void run(){

int n = 0;

Thread th = Thread.currentThread();

while(go == th){

st.setlnform(n);

System.out.print("Put: " + n + " ");

n++;

}

}

public void stop(){ go = null;

}

}

class Consumer implements Runnable{

private Store st;

private Thread go;

Consumer(Store st){

this.st = st;

go =-new Thread(this);

go.start () ;

}

public void run(){

Thread th = Thread.currentThread();

while(go == th) System.out.println("Got: " + st.getlnformf));

}

public void stop(){ go = null; }

}

class ProdCons{

public static void main(String[] args){

Store st = new Store();

Producer p = new Producer(st);

Consumer с = new Consumer(st);

try{

Thread.sleep(30);

}catch(InterruptedException ie){}

p.stop(); c.stop();

}

}

Рис. 17.4. Неузгоджена робота двох підпроцесів

В лістинзі 17.7 в клас store внесено логічне поле ready, що відмічає процес отримання і видачі інформації. Коли нова порція информації отримана від постачальника Producer, в полі ready заноситься значення true, отримувач consumer може забирати цю порцію інформації. Після видачі інформації змінна ready становиться рівною false. Але цього мало. Те, що отримувач може забрати продукт, не означає, що він дійсно забере його. Тому в кінці методу setinform() отримувач сповіщається про поступанні продукту методом notify(). Поки поле ready не прийме потрібне значення, підпроцес переводится в "залу очікування" методом wait(). Результат роботи програми з обновленим класом store показаний на рис. 17.5.

Лістинг 17.7. Узгодження отримання і видачі інформації

class Store{

private int inform = -1;

private boolean ready;

synchronized public int getlnform(){

try{

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]