Spec-Zone .ru
спецификации, руководства, описания, API
|
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements Serializable
getState()
, setState(int)
и compareAndSetState(int, int)
прослеживается относительно синхронизации. Подклассы должны быть определены как непубличные внутренние классы помощника, которые используются, чтобы реализовать свойства синхронизации их включения class. Класс AbstractQueuedSynchronizer не реализует интерфейса синхронизации. Вместо этого это определяет методы такой как acquireInterruptibly(int)
это может быть вызвано как соответствующее конкретными блокировками и связанными синхронизаторами, чтобы реализовать их открытые методы.
Этот class поддерживает или или и значение по умолчанию монопольный режим и совместно используемый режим. Когда получено в монопольном режиме, предпринятом, получает другими потоками, не может успешно выполниться. Совместно используемый режим получает многократными потоками, может (но нуждаться не), успешно выполняются. Этот class не "понимает" эти различия кроме в механическом смысле, который, когда совместно используемый режим получают, успешно выполняется, следующий поток ожидания (если Вы существуете), должен также определить, может ли это получить также. Потоки, ожидающие в различных режимах, совместно используют ту же самую очередь FIFO. Обычно, подклассы реализации поддерживают только один из этих режимов, но оба могут играть роль например в a ReadWriteLock
. Подклассы, которые поддерживают только монопольные или только совместно используемые режимы, не должны определить методы, поддерживающие неиспользованный режим.
Этот class определяет вложенный AbstractQueuedSynchronizer.ConditionObject
class, который может использоваться в качестве a Condition
реализация та, подклассами, поддерживающими монопольный режим, для который метод isHeldExclusively()
отчеты, сохранена ли синхронизация исключительно относительно текущего потока, метода release(int)
вызванный с током getState()
значение полностью выпускает этот объект, и acquire(int)
, учитывая это сохраненное значение состояния, в конечном счете восстанавливает этот объект к его предыдущему полученному состоянию. Никакой метод AbstractQueuedSynchronizer иначе не создает такое условие, так, если это ограничение не может быть встречено, не используйте это. Поведение AbstractQueuedSynchronizer.ConditionObject
зависит, конечно, от семантики его реализации синхронизатора.
Этот class обеспечивает контроль, инструментарий, и контролирующие методы для внутренней очереди, так же как подобные методы для объектов условия. Они могут быть экспортированы как требующийся в классы, используя AbstractQueuedSynchronizer для их механики синхронизации.
Сериализация этого class хранит только базовое атомарное целочисленное состояние поддержания, таким образом, у десериализованных объектов есть пустые очереди потока. Типичные подклассы, требующие сериализуемости, определят метод readObject, который восстанавливает это к известному начальному состоянию на десериализацию.
Чтобы использовать этот class в качестве основания синхронизатора, пересмотрите следующие методы, как применимые, осматривая и/или изменяя использование состояния синхронизации getState()
, setState(int)
и/или compareAndSetState(int, int)
:
UnsupportedOperationException
. Реализации этих методов должны быть внутренне ориентированы на многопотоковое исполнение, и должны вообще быть коротки и не блок. Определение этих методов является единственными поддерживаемыми средствами использования этого class. Все другие методы объявляются final, потому что они не могут быть независимо различны. Можно также найти наследованные методы от AbstractOwnableSynchronizer
полезный, чтобы отследить поток, имеющий монопольный синхронизатор. Вы поощряетесь использовать их - это позволяет контролировать и диагностические инструменты, чтобы помочь пользователям в определении, какие потоки содержат блокировки.
Даже при том, что этот class основан на внутренней очереди FIFO, он автоматически не осуществляет политики сбора FIFO. Ядро монопольной синхронизации принимает форму:
Acquire: while (!tryAcquire(arg)) { enqueue thread if it is not already queued; possibly block current thread; } Release: if (tryRelease(arg)) unblock the first queued thread;(Совместно используемый режим подобен, но может включить располагающиеся каскадом сигналы.)
Поскольку регистрации получают, вызываются перед тем, чтобы ставить в очередь недавно поток получения может неуклюже передвинуться перед другими, которые блокируются и ставятся в очередь. Однако, можно, при желании, определить tryAcquire и/или tryAcquireShared, чтобы отключить неуклюжую походку, внутренне вызывая один или больше инспекционных методов, таким образом обеспечивая справедливый порядок сбора FIFO. В частности самые справедливые синхронизаторы могут определить tryAcquire, чтобы возвратить false если hasQueuedPredecessors()
(метод, специально предназначенный, чтобы использоваться справедливыми синхронизаторами), возвращает true. Другие изменения возможны.
Пропускная способность и масштабируемость являются обычно самыми высокими для неуклюжей походки значения по умолчанию (также известный как жадный, отказ, и предотвращение конвоя) стратегия. В то время как это, как гарантируют, не будет справедливо, или более ранним потокам с очередями без исчерпания ресурсов позволяют повторно спорить прежде позже поставленные в очередь потоки, и у каждой переконкуренции есть несмещенный шанс успешно выполниться против входящих потоков. Кроме того, в то время как получает, не "вращаются" в обычном смысле, они могут выполнить многократные вызовы tryAcquire, вкрапленного другими вычислениями перед блокированием. Это приносит большинство пользы вращений, когда монопольная синхронизация только кратко сохранена без большинства долгов, когда это не. Раз так требуемый, можно увеличить это, предшествуя вызовам, чтобы получить методы с проверками "быстрого пути", возможно предварительно проверяя hasContended()
и/или hasQueuedThreads()
только сделать так, если синхронизатор вероятен не спориться.
Этот class обеспечивает эффективное и масштабируемое основание для синхронизации частично, специализируя ее диапазон использования к синхронизаторам, которые могут положиться на состояние int, получить, и выпустить параметры, и внутренний FIFO ожидает очередь. Когда это не достаточно, можно создать синхронизаторы из более низкого использования уровня atomic
классы, Ваше собственное Queue
классы, и LockSupport
блокирование поддержки.
Вот является неповторно используемая блокировка взаимного исключения class, который использует нуль значения, чтобы представить разблокированное состояние, и один, чтобы представить заблокированное состояние. В то время как неповторно используемая блокировка строго не требует записи текущего потока владельца, этот class делает так так или иначе, чтобы сделать использование легче контролировать. Это также поддерживает условия и представляет один из методов инструментария:
class Mutex implements Lock, java.io.Serializable {
// Our internal helper class
private static class Sync extends AbstractQueuedSynchronizer {
// Report whether in locked state
protected boolean isHeldExclusively() {
return getState() == 1;
}
// Acquire the lock if state is zero
public boolean tryAcquire(int acquires) {
assert acquires == 1; // Otherwise unused
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// Release the lock by setting state to zero
protected boolean tryRelease(int releases) {
assert releases == 1; // Otherwise unused
if (getState() == 0) throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
// Provide a Condition
Condition newCondition() { return new ConditionObject(); }
// Deserialize properly
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
// The sync object does all the hard work. We just forward to it.
private final Sync sync = new Sync();
public void lock() { sync.acquire(1); }
public boolean tryLock() { return sync.tryAcquire(1); }
public void unlock() { sync.release(1); }
public Condition newCondition() { return sync.newCondition(); }
public boolean isLocked() { return sync.isHeldExclusively(); }
public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
}
Вот является фиксатор class, который походит на a CountDownLatch
за исключением того, что это только требует, чтобы единственный signal стрелял. Поскольку фиксатор неисключителен, он использует shared, получают и выпускают методы.
class BooleanLatch {
private static class Sync extends AbstractQueuedSynchronizer {
boolean isSignalled() { return getState() != 0; }
protected int tryAcquireShared(int ignore) {
return isSignalled() ? 1 : -1;
}
protected boolean tryReleaseShared(int ignore) {
setState(1);
return true;
}
}
private final Sync sync = new Sync();
public boolean isSignalled() { return sync.isSignalled(); }
public void signal() { sync.releaseShared(1); }
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
}
Модификатор и Тип | Класс и Описание |
---|---|
class |
AbstractQueuedSynchronizer.ConditionObject
Реализация условия для a
AbstractQueuedSynchronizer служение в качестве основания a Lock реализация. |
Модификатор | Конструктор и Описание |
---|---|
protected |
AbstractQueuedSynchronizer()
Создает новый экземпляр AbstractQueuedSynchronizer с начальным состоянием синхронизации нуля.
|
Модификатор и Тип | Метод и Описание |
---|---|
void |
acquire(int arg)
Получает в монопольном режиме, игнорируя прерывания.
|
void |
acquireInterruptibly(int arg)
Получает в монопольном режиме, прерываясь если прервано.
|
void |
acquireShared(int arg)
Получает в совместно используемом режиме, игнорируя прерывания.
|
void |
acquireSharedInterruptibly(int arg)
Получает в совместно используемом режиме, прерываясь если прервано.
|
protected boolean |
compareAndSetState(int expect, int update)
Атомарно синхронизация наборов утверждает к данному обновленному значению, если значение текущего состояния равняется математическому ожиданию.
|
Collection<Thread> |
getExclusiveQueuedThreads()
Возвращает набор, содержащий потоки, которые могут ожидать, чтобы получить в монопольном режиме.
|
Поток |
getFirstQueuedThread()
Возвращает первый (дольше всего ожидающий) поток в очереди, или
null если никакие потоки в настоящий момент не ставятся в очередь. |
Collection<Thread> |
getQueuedThreads()
Возвращает набор, содержащий потоки, которые могут ожидать, чтобы получить.
|
int |
getQueueLength()
Возвращает оценку числа потоков, ожидающих, чтобы получить.
|
Collection<Thread> |
getSharedQueuedThreads()
Возвращает набор, содержащий потоки, которые могут ожидать, чтобы получить в совместно используемом режиме.
|
protected int |
getState()
Возвращает текущую стоимость состояния синхронизации.
|
Collection<Thread> |
getWaitingThreads(AbstractQueuedSynchronizer.ConditionObject condition)
Возвращает набор, содержащий те потоки, которые могут ожидать на данном условии, связанном с этим синхронизатором.
|
int |
getWaitQueueLength(AbstractQueuedSynchronizer.ConditionObject condition)
Возвращает оценку числа потоков, ожидающих на данном условии, связанном с этим синхронизатором.
|
boolean |
hasContended()
Запросы, спорили ли какие-либо потоки когда-либо, чтобы получить этот синхронизатор; это - то, если получать метод когда-либо блокировал.
|
boolean |
hasQueuedPredecessors()
Запросы, ожидали ли какие-либо потоки, чтобы получить дольше чем текущий поток.
|
boolean |
hasQueuedThreads()
Запросы, ожидают ли какие-либо потоки, чтобы получить.
|
boolean |
hasWaiters(AbstractQueuedSynchronizer.ConditionObject condition)
Запросы, ожидают ли какие-либо потоки на данном условии, связанном с этим синхронизатором.
|
protected boolean |
isHeldExclusively()
Возвраты
true если синхронизация считается исключительно относительно текущего (вызов) потоком. |
boolean |
isQueued(Thread thread)
Возвращает true, если данный поток в настоящий момент ставится в очередь.
|
boolean |
owns(AbstractQueuedSynchronizer.ConditionObject condition)
Запросы, использует ли данный ConditionObject этот синхронизатор в качестве своей блокировки.
|
boolean |
release(int arg)
Выпуски в монопольном режиме.
|
boolean |
releaseShared(int arg)
Выпуски в совместно используемом режиме.
|
protected void |
setState(int newState)
Устанавливает значение состояния синхронизации.
|
Строка |
toString()
Возвращает строку, идентифицирующую этот синхронизатор, так же как его состояние.
|
protected boolean |
tryAcquire(int arg)
Попытки получить в монопольном режиме.
|
boolean |
tryAcquireNanos(int arg, long nanosTimeout)
Попытки получить в монопольном режиме, прерываясь если прервано, и перестав работать, если данный тайм-аут протекает.
|
protected int |
tryAcquireShared(int arg)
Попытки получить в совместно используемом режиме.
|
boolean |
tryAcquireSharedNanos(int arg, long nanosTimeout)
Попытки получить в совместно используемом режиме, прерываясь если прервано, и перестав работать, если данный тайм-аут протекает.
|
protected boolean |
tryRelease(int arg)
Попытки установить состояние, чтобы отразить выпуск в монопольном режиме.
|
protected boolean |
tryReleaseShared(int arg)
Попытки установить состояние, чтобы отразить выпуск в совместно используемом режиме.
|
getExclusiveOwnerThread, setExclusiveOwnerThread
protected AbstractQueuedSynchronizer()
protected final int getState()
protected final void setState(int newState)
newState
- новое значение состоянияprotected final boolean compareAndSetState(int expect, int update)
expect
- математическое ожиданиеupdate
- новое значениеprotected boolean tryAcquire(int arg)
Этот метод всегда вызывается выполнением потока, получают. Если этот отказ отчетов метода, получать метод может поставить поток в очередь, если это уже не ставится в очередь, пока это не сообщается выпуском от некоторого другого потока. Это может использоваться, чтобы реализовать метод Lock.tryLock()
.
Броски реализации по умолчанию UnsupportedOperationException
.
arg
- получать параметр. Это значение всегда является тем, которое передают к получать методу, или является значением, на котором экономят, запись в условие ожидает. Значение иначе неинтерпретируется и может представить что-либо, что Вы любите.true
в случае успеха. На успех был получен этот объект.IllegalMonitorStateException
- если получение поместило бы этот синхронизатор в недопустимое состояние. Это исключение должно быть выдано непротиворечивым способом для синхронизации, чтобы работать правильно.UnsupportedOperationException
- если монопольный режим не поддерживаетсяprotected boolean tryRelease(int arg)
Этот метод всегда вызывается выпуском выполнения потока.
Броски реализации по умолчанию UnsupportedOperationException
.
arg
- параметр выпуска. Это значение всегда является тем, которое передают к методу выпуска, или значение текущего состояния после записи в условие ожидает. Значение иначе неинтерпретируется и может представить что-либо, что Вы любите.true
если этот объект находится теперь в полностью выпущенном состоянии, так, чтобы любые потоки ожидания могли попытаться получить; и false
иначе.IllegalMonitorStateException
- если выпуск поместил бы этот синхронизатор в недопустимое состояние. Это исключение должно быть выдано непротиворечивым способом для синхронизации, чтобы работать правильно.UnsupportedOperationException
- если монопольный режим не поддерживаетсяprotected int tryAcquireShared(int arg)
Этот метод всегда вызывается выполнением потока, получают. Если этот отказ отчетов метода, получать метод может поставить поток в очередь, если это уже не ставится в очередь, пока это не сообщается выпуском от некоторого другого потока.
Броски реализации по умолчанию UnsupportedOperationException
.
arg
- получать параметр. Это значение всегда является тем, которое передают к получать методу, или является значением, на котором экономят, запись в условие ожидает. Значение иначе неинтерпретируется и может представить что-либо, что Вы любите.IllegalMonitorStateException
- если получение поместило бы этот синхронизатор в недопустимое состояние. Это исключение должно быть выдано непротиворечивым способом для синхронизации, чтобы работать правильно.UnsupportedOperationException
- если совместно использованный режим не поддерживаетсяprotected boolean tryReleaseShared(int arg)
Этот метод всегда вызывается выпуском выполнения потока.
Броски реализации по умолчанию UnsupportedOperationException
.
arg
- параметр выпуска. Это значение всегда является тем, которое передают к методу выпуска, или значение текущего состояния после записи в условие ожидает. Значение иначе неинтерпретируется и может представить что-либо, что Вы любите.true
если этот выпуск совместно используемого режима может разрешить, чтобы ожидание получило (совместно использованный или монопольный), чтобы успешно выполниться; и false
иначеIllegalMonitorStateException
- если выпуск поместил бы этот синхронизатор в недопустимое состояние. Это исключение должно быть выдано непротиворечивым способом для синхронизации, чтобы работать правильно.UnsupportedOperationException
- если совместно использованный режим не поддерживаетсяprotected boolean isHeldExclusively()
true
если синхронизация считается исключительно относительно текущего (вызов) потоком. Этот метод вызывается на каждый звонок в неожидание AbstractQueuedSynchronizer.ConditionObject
метод. (Ожидающие методы вместо этого вызывают release(int)
.) Броски реализации по умолчанию UnsupportedOperationException
. Этот метод вызывается внутренне только в пределах AbstractQueuedSynchronizer.ConditionObject
методы, так не должен быть определен, если условия не используются.
true
если синхронизация сохранена исключительно; false
иначеUnsupportedOperationException
- если условия не поддерживаютсяpublic final void acquire(int arg)
tryAcquire(int)
, возврат на успехе. Иначе поток ставится в очередь, возможно неоднократно блокируя и разблокируя, вызывая tryAcquire(int)
до успеха. Этот метод может использоваться, чтобы реализовать метод Lock.lock()
.arg
- получать параметр. Это значение передается tryAcquire(int)
но иначе неинтерпретируется и может представить что-либо, что Вы любите.public final void acquireInterruptibly(int arg) throws InterruptedException
tryAcquire(int)
, возврат на успехе. Иначе поток ставится в очередь, возможно неоднократно блокируя и разблокируя, вызывая tryAcquire(int)
до успеха или потока прерывается. Этот метод может использоваться, чтобы реализовать метод Lock.lockInterruptibly()
.arg
- получать параметр. Это значение передается tryAcquire(int)
но иначе неинтерпретируется и может представить что-либо, что Вы любите.InterruptedException
- если текущий поток прерываетсяpublic final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException
tryAcquire(int)
, возврат на успехе. Иначе, поток ставится в очередь, возможно неоднократно блокируя и разблокируя, вызывая tryAcquire(int)
до успеха или потока прерывается, или тайм-аут протекает. Этот метод может использоваться, чтобы реализовать метод Lock.tryLock(long, TimeUnit)
.arg
- получать параметр. Это значение передается tryAcquire(int)
но иначе неинтерпретируется и может представить что-либо, что Вы любите.nanosTimeout
- максимальное количество наносекунд, чтобы ожидатьtrue
если получено; false
если синхронизированныйInterruptedException
- если текущий поток прерываетсяpublic final boolean release(int arg)
tryRelease(int)
возвращает true. Этот метод может использоваться, чтобы реализовать метод Lock.unlock()
.arg
- параметр выпуска. Это значение передается tryRelease(int)
но иначе неинтерпретируется и может представить что-либо, что Вы любите.tryRelease(int)
public final void acquireShared(int arg)
tryAcquireShared(int)
, возврат на успехе. Иначе поток ставится в очередь, возможно неоднократно блокируя и разблокируя, вызывая tryAcquireShared(int)
до успеха.arg
- получать параметр. Это значение передается tryAcquireShared(int)
но иначе неинтерпретируется и может представить что-либо, что Вы любите.public final void acquireSharedInterruptibly(int arg) throws InterruptedException
tryAcquireShared(int)
, возврат на успехе. Иначе поток ставится в очередь, возможно неоднократно блокируя и разблокируя, вызывая tryAcquireShared(int)
до успеха или потока прерывается.arg
- получать параметр Это значение передается tryAcquireShared(int)
но иначе неинтерпретируется и может представить что-либо, что Вы любите.InterruptedException
- если текущий поток прерываетсяpublic final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException
tryAcquireShared(int)
, возврат на успехе. Иначе, поток ставится в очередь, возможно неоднократно блокируя и разблокируя, вызывая tryAcquireShared(int)
до успеха или потока прерывается, или тайм-аут протекает.arg
- получать параметр. Это значение передается tryAcquireShared(int)
но иначе неинтерпретируется и может представить что-либо, что Вы любите.nanosTimeout
- максимальное количество наносекунд, чтобы ожидатьtrue
если получено; false
если синхронизированныйInterruptedException
- если текущий поток прерываетсяpublic final boolean releaseShared(int arg)
tryReleaseShared(int)
возвращает true.arg
- параметр выпуска. Это значение передается tryReleaseShared(int)
но иначе неинтерпретируется и может представить что-либо, что Вы любите.tryReleaseShared(int)
public final boolean hasQueuedThreads()
true
возврат не гарантирует, что любой другой поток будет когда-либо получать. В этой реализации эта работа возвращается в постоянное время.
true
если могут быть другие потоки, ожидающие, чтобы получитьpublic final boolean hasContended()
В этой реализации эта работа возвращается в постоянное время.
true
если когда-либо была конкуренцияpublic final Thread getFirstQueuedThread()
null
если никакие потоки в настоящий момент не ставятся в очередь. В этой реализации эта работа обычно возвращается в постоянное время, но может выполнить итерации на конкуренцию, если другие потоки одновременно изменяют очередь.
null
если никакие потоки в настоящий момент не ставятся в очередьpublic final boolean isQueued(Thread thread)
Эта реализация пересекает очередь, чтобы определить присутствие данного потока.
thread
- потокtrue
если данный поток находится на очередиNullPointerException
- если поток является нулемpublic final boolean hasQueuedPredecessors()
Вызов этого метода эквивалентен (но может быть более эффективным чем):
getFirstQueuedThread() != Thread.currentThread() &&
hasQueuedThreads()
Отметьте это, потому что отмены из-за прерываний и тайм-аутов могут произойти в любое время, a true
возврат не гарантирует, что некоторый другой поток получит перед текущим потоком. Аналогично, для другого потока возможно выиграть гонки, чтобы ставить в очередь после того, как этот метод возвратился false
, из-за очереди, являющейся пустым.
Этот метод разрабатывается, чтобы использоваться справедливым синхронизатором, чтобы избежать неуклюже передвигаться. Такой синхронизатор tryAcquire(int)
метод должен возвратиться false
, и tryAcquireShared(int)
метод должен возвратить отрицательную величину, если этот метод возвращается true
(если это не повторно используемое, получают). Например, tryAcquire
метод для справедливого, повторно используемого, монопольного синхронизатора режима мог бы быть похожим на это:
protected boolean tryAcquire(int arg) {
if (isHeldExclusively()) {
// A reentrant acquire; increment hold count
return true;
} else if (hasQueuedPredecessors()) {
return false;
} else {
// try to acquire normally
}
}
true
если есть поток с очередями, предшествующий текущему потоку, и false
если текущий поток во главе очереди, или очередь пустаpublic final int getQueueLength()
public final Collection<Thread> getQueuedThreads()
public final Collection<Thread> getExclusiveQueuedThreads()
getQueuedThreads()
за исключением того, что это только возвращается, те потоки, ожидающие из-за монопольного, получают.public final Collection<Thread> getSharedQueuedThreads()
getQueuedThreads()
за исключением того, что это только возвращается, те потоки, ожидающие из-за совместно используемого, получают.public String toString()
"State ="
сопровождаемый текущей стоимостью getState()
, и также "nonempty"
или "empty"
в зависимости от того, пуста ли очередь.public final boolean owns(AbstractQueuedSynchronizer.ConditionObject condition)
condition
- условиеNullPointerException
- если условие является нулемpublic final boolean hasWaiters(AbstractQueuedSynchronizer.ConditionObject condition)
condition
- условиеIllegalMonitorStateException
- если монопольная синхронизация не сохраненаIllegalArgumentException
- если данное условие не связывается с этим синхронизаторомNullPointerException
- если условие является нулемpublic final int getWaitQueueLength(AbstractQueuedSynchronizer.ConditionObject condition)
condition
- условиеIllegalMonitorStateException
- если монопольная синхронизация не сохраненаIllegalArgumentException
- если данное условие не связывается с этим синхронизаторомNullPointerException
- если условие является нулемpublic final Collection<Thread> getWaitingThreads(AbstractQueuedSynchronizer.ConditionObject condition)
condition
- условиеIllegalMonitorStateException
- если монопольная синхронизация не сохраненаIllegalArgumentException
- если данное условие не связывается с этим синхронизаторомNullPointerException
- если условие является нулем
Для дальнейшей ссылки API и документации разработчика, см. Java Документация SE. Та документация содержит более подробные, предназначенные разработчиком описания, с концептуальными краткими обзорами, определениями сроков, обходных решений, и рабочих примеров кода.
Авторское право © 1993, 2013, Oracle и/или его филиалы. Все права защищены.
Проект сборка-b92