Spec-Zone .ru
спецификации, руководства, описания, API
|
Синхронизируемый код полагается на простой вид повторно используемой блокировки. Этот вид блокировки удобен, но имеет много ограничений. Более сложные идиомы блокировки поддерживаются java.util.concurrent.locks
пакет. Мы не будем исследовать этот пакет подробно, но вместо этого сосредоточимся на его самом основном интерфейсе, Lock
Lock
объекты работают очень как неявные блокировки, используемые синхронизируемым кодом. Как с неявными блокировками, только одному потоку может принадлежать a Lock
объект за один раз. Lock
объекты также поддерживают a wait/notify
механизм, через их связанное Condition
Самое большое преимущество Lock
объекты по неявным блокировкам являются своей возможностью отступить из попытки получить блокировку. tryLock
метод отступает, если блокировка сразу не доступна или прежде, чем тайм-аут истечет (если определено). lockInterruptibly
метод отступает, если другой поток отправляет прерывание прежде, чем блокировка будет получена.
Давайте использовать Lock
объекты решить проблему мертвой блокировки мы видели в Живом. Альфонс и Гастон обучали себя замечать, когда друг собирается поклониться. Мы моделируем это улучшение, требуя что наш Friend
объекты должны получить блокировки для обоих участников перед продолжением поклона. Вот исходный код для улучшенной модели,
. Чтобы демонстрировать универсальность этой идиомы, мы предполагаем, что Альфонс и Гастон столь страстно увлекаются их новооткрытой возможностью поклониться безопасно, что они не могут прекратить кланяться друг другу:Safelock
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.Random; public class Safelock { static class Friend { private final String name; private final Lock lock = new ReentrantLock(); public Friend(String name) { this.name = name; } public String getName() { return this.name; } public boolean impendingBow(Friend bower) { Boolean myLock = false; Boolean yourLock = false; try { myLock = lock.tryLock(); yourLock = bower.lock.tryLock(); } finally { if (! (myLock && yourLock)) { if (myLock) { lock.unlock(); } if (yourLock) { bower.lock.unlock(); } } } return myLock && yourLock; } public void bow(Friend bower) { if (impendingBow(bower)) { try { System.out.format("%s: %s has" + " bowed to me!%n", this.name, bower.getName()); bower.bowBack(this); } finally { lock.unlock(); bower.lock.unlock(); } } else { System.out.format("%s: %s started" + " to bow to me, but saw that" + " I was already bowing to" + " him.%n", this.name, bower.getName()); } } public void bowBack(Friend bower) { System.out.format("%s: %s has" + " bowed back to me!%n", this.name, bower.getName()); } } static class BowLoop implements Runnable { private Friend bower; private Friend bowee; public BowLoop(Friend bower, Friend bowee) { this.bower = bower; this.bowee = bowee; } public void run() { Random random = new Random(); for (;;) { try { Thread.sleep(random.nextInt(10)); } catch (InterruptedException e) {} bowee.bow(bower); } } } public static void main(String[] args) { final Friend alphonse = new Friend("Alphonse"); final Friend gaston = new Friend("Gaston"); new Thread(new BowLoop(alphonse, gaston)).start(); new Thread(new BowLoop(gaston, alphonse)).start(); } }