Page 141 - 4868
P. 141
139 Ошибка! Стиль не определен.
notifyAll() та notify(). Проте, об’єкти в мові Java відрізняються від
класичної реалізації монітора наступними трьома важливими пунктами, що
потенційно можуть впливати на безпеку потоків:
1. Поля не обов’язково повинні бути закритими (private).
2. Методи не зобов’язані бути синхронізованими (synchronized).
3. Клієнтам доступне керування вбудованим блокуванням.
Ці пункти свідчать про явне нехтування вимогами безпеки, викладеними
Пером Брінчем Хансеном (Fer Brinch Hansen) і Тоні Хоаром (Тоnу Ноаrе) в
1970-х роках.
Щоб уникнути пошкодження даних, що спільно використовуються
декількома потоками, необхідно синхронізувати доступ до них із різних
потоків. У наступному прикладі програми імітується робота банку з
декількома рахунками. Згенеруємо випадковим чином декілька транзакції,
що переводять гроші з одного рахунку на інший. Кожна транзакція
переміщає довільну суму грошей з рахунку, що обслуговується поточним
потоком, на іншій довільно обираний рахунок.
У коді, що імітує роботу банку визначено клас Bank та описано метод
transfer(). Даний метод переміщує деяку суму грошей з одного рахунку
на інший. Нижче наведено можливий вихідний код методу transfer() з
класу Bank.
public void transfer(int from, int to, double amount) {
System.out.println(Thread.currentThread());
accounts[from] = accounts[from] - amount;
System.out.printf("%10.2f з %d до %d", amount, from, to);
accounts[to] = accounts[to]+amount;
System.out.printf("Загальний баланс:%10.2f%n",
getTotalBalance());
}
Нижче наведено вихідний код класу TransferRunnable. Його метод
run() виконує перевід грошей з фіксованого банківського рахунку. Для
кожної транзакції метод run() вибирає випадковий рахунок і довільну суму,
викликає метод transfer() для об’єкта Bank, а потім переводить потік в
стан очікування.
class TransferRunnable implements Runnable {
public void run() {
try {
int toAccount = (int) (bank.size() * Math.random());
double amount = maxAmount * Math.random();
bank.transfer(fromAccount, toAccount, amount);
Thread.sleep((int) (DELAY * Math.random()));
} catch (InterruptedException e) { }
}
}
Під час виконання даної програми, невідомо, яка саме сума знаходиться