Object.avt

Переключить прокрутку окна
Загрузить этот исходный код

/*
    Исходный код среды исполнения ПВТ-ОО.

    Этот исходный код является частью проекта ПВТ-ОО.

    Copyright © 2021 Малик Разработчик

    Это свободная программа: вы можете перераспространять её и/или
    изменять её на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она может быть полезна,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <http://www.gnu.org/licenses/>.
*/

package avt.lang;

import platform.dependent.*;

/**
 * Класс <code>Object</code> является корнем всей иерархии типов программы.
 * Каждый класс имеет <code>Object</code> в качестве суперкласса.
 * Все объекты, включая массивы и структуры, реализуют методы этого класса.
 *
 * С каждым объектом связан монитор — объект синхронизации в многопоточном приложении.
 * Этот монитор уникален для каждого объекта.
 * @see Class
 * @see Thread
 */
public class Object
{
    private long fldRefCountFromOthers;
    private long fldRefCountFromObjects;
    private long fldClassOffset;
    private Monitor fldMonitor;

    /**
     * Создаёт новый объект. Этот конструктор явно или неявно вызывается из всех других конструкторов.
     * Исключением являются массивы: для них не вызывается какой-либо конструктор, поскольку массивы в ПВТ-ОО имеют иной механизм инициализации.
     * @see #afterConstruction()
     * @see #beforeDestruction()
     */
    public () {  }

    /**
     * Показывает, когда некоторый другой объект «равен» этому. Этот метод реализует отношение равенства:
     * </p><ul><li>
     * Оно <em>рефлексивно</em>: для любой ссылки <code>x</code>, <code>x.equals(x)</code> должно возвращать <code>true</code>.
     * </li><li>
     * Оно <em>симметрично</em>: для любых ссылок <code>x</code> и <code>y</code>, <code>x.equals(y) == y.equals(x)</code>.
     * </li><li>
     * Оно <em>транзитивно</em>: для любых ссылок <code>x</code>, <code>y</code> и <code>z</code>, если <code>x.equals(y)</code>
     * и <code>y.equals(z)</code> возвращают <code>true</code>, то и <code>x.equals(z)</code> так же должно возвращать <code>true</code>.
     * </li><li>
     * Оно <em>консистентно</em>: если содержимое ссылок <code>x</code> и <code>y</code> не изменяется, то и возвращаемое значение <code>x.equals(y)</code>
     * не изменяется даже при повторяющихся вызовах.
     * </li><li>
     * Для любой ссылки <code>x</code>, <code>x.equals(null)</code> должно возвращать <code>false</code>.
     * </li></ul><p>
     * Использование этого метода может заменить собой операцию сравнения двух объектных ссылок,
     * поскольку если <code>(x == y)</code>, то и <code>(x.equals(y) == true)</code>.
     *
     * Этот метод нужно так же переопределять, если переопределён метод <code>{@link #hashCodeAsLong() hashCodeAsLong()}</code>.
     *
     * Реализация данного метода в классе <code>Object</code> возвращает результат сравнения двух ссылок: <code>anot == this</code>.
     * @param anot объект, с которым производится «сравнение» этого объекта.
     * @return <code>true</code>, если объекты «равны», <code>false</code> — во всех остальных случаях.
     * @see #hashCodeAsLong()
     */
    public boolean equals(Object anot) { return anot == this; }

    /**
     * Возвращает контрольную сумму в виде значения типа <code>int</code> для этого объекта. Подклассы могут переопределить этот метод в одном из следующих случаев:
     * </p><ul><li>
     * если используется свой алгоритм вычисления контрольной суммы объекта;
     * </li><li>
     * если есть возможность более быстрого вычисления контрольной суммы объекта.
     * </li></ul><p>
     * Этот метод можно переопределить только в том случае, если переопределены методы <code>{@link #hashCodeAsLong() hashCodeAsLong()}</code> и <code>{@link #equals(Object) equals(Object)}</code>.
     * При переопределении и реализации этого метода следует руководствоваться тем же, что и при реализации метода <code>hashCodeAsLong()</code>.
     *
     * Реализация данного метода в классе <code>Object</code> такова:
     *
     * <code>long hash = hashCodeAsLong();<br />
     * return (int) (hash ^ (hash >> 32));</code>
     * @return контрольную сумму типа <code>int</code>.
     * @see #equals(Object)
     * @see #hashCodeAsLong()
     */
    public int hashCode() {
        long hash = hashCodeAsLong();
        return (int) (hash ^ (hash >> 32));
    }

    /**
     * Возвращает контрольную сумму в виде значения типа <code>long</code> для этого объекта. Такие классы как <code>{@link avt.util.Hashtable Hashtable}</code> и <code>{@link avt.util.Vector Vector}</code>
     * из пакета <code>{@link avt.util avt.util}</code> используют этот метод.
     *
     * При переопределении и реализации этого метода следует руководствоваться следующим:
     * </p><ul><li>
     * При каждом вызове этого метода должно возвращаться одно и то же значение, даже если данные объекта были модифицированы.
     * Соответственно, при реализации объектов, поддерживающих модифицирование своих данных, данный метод не должен пользоваться данными, которые использует метод <code>equals</code>.
     * </li><li>
     * Если два объекта «равны» согласно реализации метода <code>equals</code>, то и контрольные суммы этих объектов так же должны быть равны.
     * Данное требование не распространяется на объекты, данные которых были модифицированы.
     * </li><li>
     * Если два объекта «не равны» согласно реализации метода <code>equals</code>, то их контрольные суммы не обязаны быть неравными.
     * </li></ul><p>
     * Этот метод нужно так же переопределять, если переопределён метод <code>{@link #equals(Object) equals(Object)}</code>.
     *
     * Реализация данного метода в классе <code>Object</code> возвращает уникальное ненулевое значение, связанное с этим объектом.
     * @return контрольную сумму типа <code>long</code>.
     * @see #equals(Object)
     */
    public long hashCodeAsLong() { return System.identityHashCode(this); }

    /**
     * Возвращает контрольную сумму в виде значения типа <code>long2</code> для этого объекта. Подклассы могут переопределить этот метод в одном из следующих случаев:
     * </p><ul><li>
     * если используется свой алгоритм вычисления контрольной суммы объекта;
     * </li><li>
     * если есть возможность получения контрольной суммы типа <code>long2</code>;
     * </li><li>
     * если есть возможность более быстрого вычисления контрольной суммы объекта.
     * </li></ul><p>
     * Этот метод можно переопределить только в том случае, если переопределены методы <code>{@link #hashCodeAsLong() hashCodeAsLong()}</code> и <code>{@link #equals(Object) equals(Object)}</code>.
     * При переопределении и реализации этого метода следует руководствоваться тем же, что и при реализации метода <code>hashCodeAsLong()</code>.
     *
     * Реализация данного метода в классе <code>Object</code> вызывает метод <code>hashCodeAsLong()</code> и приводит его результат к типу <code>long2</code>.
     * @return контрольную сумму типа <code>long2</code>.
     * @see #equals(Object)
     * @see #hashCodeAsLong()
     */
    public long2 hashCodeAsLong2() { return (long2) hashCodeAsLong(); }

    /**
     * Возвращает контрольную сумму в виде значения типа <code>long4</code> для этого объекта. Подклассы могут переопределить этот метод в одном из следующих случаев:
     * </p><ul><li>
     * если используется свой алгоритм вычисления контрольной суммы объекта;
     * </li><li>
     * если есть возможность получения контрольной суммы типа <code>long4</code>;
     * </li><li>
     * если есть возможность более быстрого вычисления контрольной суммы объекта.
     * </li></ul><p>
     * Этот метод можно переопределить только в том случае, если переопределены методы <code>{@link #hashCodeAsLong() hashCodeAsLong()}</code>, <code>{@link #hashCodeAsLong2() hashCodeAsLong2()}</code> и
     * <code>{@link #equals(Object) equals(Object)}</code>.
     * При переопределении и реализации этого метода следует руководствоваться тем же, что и при реализации метода <code>hashCodeAsLong()</code>.
     *
     * Реализация данного метода в классе <code>Object</code> вызывает метод <code>hashCodeAsLong2()</code> и приводит его результат к типу <code>long4</code>.
     * @return контрольную сумму типа <code>long4</code>.
     * @see #equals(Object)
     * @see #hashCodeAsLong()
     * @see #hashCodeAsLong2()
     */
    public long4 hashCodeAsLong4() { return (long4) hashCodeAsLong2(); }

    /**
     * Возвращает контрольную сумму в виде значения типа <code>long8</code> для этого объекта. Подклассы могут переопределить этот метод в одном из следующих случаев:
     * </p><ul><li>
     * если используется свой алгоритм вычисления контрольной суммы объекта;
     * </li><li>
     * если есть возможность получения контрольной суммы типа <code>long8</code>;
     * </li><li>
     * если есть возможность более быстрого вычисления контрольной суммы объекта.
     * </li></ul><p>
     * Этот метод можно переопределить только в том случае, если переопределены методы <code>{@link #hashCodeAsLong() hashCodeAsLong()}</code>, <code>{@link #hashCodeAsLong2() hashCodeAsLong2()}</code>,
     * <code>{@link #hashCodeAsLong4() hashCodeAsLong4()}</code> и <code>{@link #equals(Object) equals(Object)}</code>.
     * При переопределении и реализации этого метода следует руководствоваться тем же, что и при реализации метода <code>hashCodeAsLong()</code>.
     *
     * Реализация данного метода в классе <code>Object</code> вызывает метод <code>hashCodeAsLong4()</code> и приводит его результат к типу <code>long8</code>.
     * @return контрольную сумму типа <code>long8</code>.
     * @see #equals(Object)
     * @see #hashCodeAsLong()
     * @see #hashCodeAsLong2()
     * @see #hashCodeAsLong4()
     */
    public long8 hashCodeAsLong8() { return (long8) hashCodeAsLong4(); }

    /**
     * Возвращает текстовое представление объекта. Иными словами, этот метод возвращает строку, которая «текстовым образом представляет» этот объект.
     * Результат не обязательно должен быть подробным, но должен быть информативным для читателя.
     * Этот метод рекомендуется переопределять всем подклассам.
     *
     * Реализация данного метода в классе <code>Object</code> возвращает конкатенацию трёх элементов: канонического имени класса объекта, символа «@» и
     * шестнадцатеричного представления беззнакового значения контрольной суммы типа <code>long</code> для этого объекта. Другими словами, возвращается
     * значение, эквивалентное следующему:
     *
     * <code>getClass().canonicalName + '@' + Long.toHexString(hashCodeAsLong())</code>
     * @return текстовое представление объекта.
     */
    public String toString() { return (new StringBuilder() + getClass().canonicalName + '@' + Long.toHexString(hashCodeAsLong())).toString(); }

    /**
     * Пробуждает один поток исполнения, ожидающий на мониторе этого объекта. Если какие-либо потоки исполнения ожидают на мониторе, то один из них выбирается для пробуждения.
     * Какой из них будет выбран — зависит от реализации. Поток исполнения ожидает на мониторе при вызове одного из методов <code>wait</code>.
     *
     * Пробужденный поток исполнения не сразу получает управление, а лишь после того, как текущий поток исполнения перестанет быть владельцем монитора, связанным с этим объектом.
     * Этот метод может быть вызван только если текущий поток исполнения является владельцем монитора этого объекта.
     * Поток исполнения становится владельцем монитора в одном из следующих случаев:
     * </p><ul><li>
     * Выполняет тело управляющей конструкции <code>synchronized</code> или <code>synchronized with</code>, которая синхронизирует выполнение кода на мониторе этого объекта;
     * </li><li>
     * Выполняет тело синхронизированного инстанционного метода этого объекта;
     * </li><li>
     * Для объектов типа <code>Class</code>: выполняет тело синхронизированного статичного метода этого класса.
     * </li></ul><p>
     * Только один поток исполнения одновременно может владеть монитором объекта.
     * @throws IllegalMonitorStateException если текущий поток исполнения не владеет монитором этого объекта.
     * @see #notify(Thread)
     * @see #notifyAll()
     * @see #wait()
     */
    public final void notify() {
        Monitor monitor = fldMonitor;
        if(monitor == null)
        {
            throw new IllegalMonitorStateException("текущий поток исполнения не владеет этим монитором");
        }
        monitor.notify(false, 0L);
    }

    /**
     * Пробуждает заданный поток исполнения, ожидающий на мониторе этого объекта. Если какие-либо потоки исполнения ожидают на мониторе, то один из них выбирается для пробуждения,
     * однако предпочтение отдаётся тому потоку, который был передан в качестве аргумента этому методу. Другими словами, если заданный в качестве аргумента поток исполнения ожидает
     * на мониторе, то будет пробужден именно он. Иначе — любой другой ожидающий поток исполнения. Поток исполнения ожидает на мониторе при вызове одного из методов <code>wait</code>.
     *
     * Пробужденный поток исполнения не сразу получает управление, а лишь после того, как текущий поток исполнения перестанет быть владельцем монитора, связанным с этим объектом.
     * Этот метод может быть вызван только если текущий поток исполнения является владельцем монитора этого объекта.
     * О том, как поток исполнения становится владельцем монитора, можно узнать в описании метода <code>notify()</code>.
     * @param notifying поток исполнения, который следует пробудить в первую очередь
     * @throws IllegalMonitorStateException если текущий поток исполнения не владеет монитором этого объекта.
     * @see #notify()
     * @see #notifyAll()
     * @see #wait()
     */
    public final void notify(Thread notifying) {
        Monitor monitor = fldMonitor;
        if(monitor == null)
        {
            throw new IllegalMonitorStateException("текущий поток исполнения не владеет этим монитором");
        }
        monitor.notify(false, notifying == null ? 0L : notifying.threadId);
    }

    /**
     * Пробуждает все потоки исполнения, ожидающие на мониторе этого объекта. Поток исполнения ожидает на мониторе при вызове одного из методов <code>wait</code>.
     *
     * Пробужденные потоки исполнения не сразу получают управление, а лишь после того, как текущий поток исполнения перестанет быть владельцем монитора, связанным с этим объектом,
     * причём управление получит только один из этих потоков до тех пор, пока он не перестанет быть владельцем монитора,
     * после чего управление получит другой поток до тех пор, пока он не перестанет быть владельцем монитора и т. д.
     * Этот метод может быть вызван только если текущий поток исполнения является владельцем монитора этого объекта.
     * О том, как поток исполнения становится владельцем монитора, можно узнать в описании метода <code>notify()</code>.
     * @throws IllegalMonitorStateException если текущий поток исполнения не владеет монитором этого объекта.
     * @see #notify()
     * @see #notify(Thread)
     * @see #wait()
     */
    public final void notifyAll() {
        Monitor monitor = fldMonitor;
        if(monitor == null)
        {
            throw new IllegalMonitorStateException("текущий поток исполнения не владеет этим монитором");
        }
        monitor.notify(true, 0L);
    }

    /**
     * Заставляет текущий поток исполнения ждать на мониторе этого объекта до тех пор, пока другой поток не вызовет метод <code>notify()</code> или <code>notifyAll()</code> для этого объекта.
     * Другими словами, этот метод ведёт себя подобно вызову <code>wait(0L)</code> или <code>wait(0L, 0)</code>.
     *
     * Текущий поток исполнения должен владеть монитором этого объекта. Поток перестаёт быть владельцем монитора, уходит в спячку, а после пробуждения — снова становится владельцем этого монитора,
     * после чего метод <code>wait</code> возвращает управление. О том, как поток исполнения становится владельцем монитора, можно узнать в описании метода <code>notify()</code>.
     * @throws IllegalMonitorStateException если текущий поток исполнения не владеет монитором этого объекта.
     * @throws InterruptedException если текущий поток исполнения был прерван. <em>Статус прерывания</em> сбрасывается после того, как текущий поток исполнения станет владельцем монитора этого объекта,
     * и перед тем, как это исключение будет возбуждено.
     * @see #notify()
     * @see #wait(long)
     * @see #wait(long, int)
     */
    public final void wait() throws InterruptedException {
        Monitor monitor = fldMonitor;
        if(monitor == null)
        {
            throw new IllegalMonitorStateException("текущий поток исполнения не владеет этим монитором");
        }
        monitor.wait(0i, Thread.current().waitableHandler);
    }

    /**
     * Заставляет текущий поток исполнения ждать на мониторе этого объекта до тех пор, пока другой поток не вызовет метод <code>notify()</code> или <code>notifyAll()</code> для этого объекта, но не дольше
     * заданного времени. Если заданное время ожидания равно нулю, то ожидание будет длиться до тех пор, пока другой поток не вызовет метод <code>notify()</code> или <code>notifyAll()</code> для этого объекта.
     *
     * Текущий поток исполнения должен владеть монитором этого объекта. Поток перестаёт быть владельцем монитора, уходит в спячку, а после пробуждения — снова становится владельцем этого монитора,
     * после чего метод <code>wait</code> возвращает управление. О том, как поток исполнения становится владельцем монитора, можно узнать в описании метода <code>notify()</code>.
     * @param timeInMillis время ожидания в миллисекундах. Если этот аргумент равен нулю, то он игнорируется.
     * @throws IllegalArgumentException если <code>timeInMillis</code> отрицательный.
     * @throws IllegalMonitorStateException если текущий поток исполнения не владеет монитором этого объекта.
     * @throws InterruptedException если текущий поток исполнения был прерван. <em>Статус прерывания</em> сбрасывается после того, как текущий поток исполнения станет владельцем монитора этого объекта,
     * и перед тем, как это исключение будет возбуждено.
     * @see #notify()
     * @see #wait()
     * @see #wait(long, int)
     */
    public final void wait(long timeInMillis) throws InterruptedException {
        if(timeInMillis < 0L)
        {
            throw new IllegalArgumentException("аргумент timeInMillis не может быть отрицательным");
        }
        Monitor monitor = fldMonitor;
        if(monitor == null)
        {
            throw new IllegalMonitorStateException("текущий поток исполнения не владеет этим монитором");
        }
        monitor.wait(timeInMillis, Thread.current().waitableHandler);
    }

    /**
     * Заставляет текущий поток исполнения ждать на мониторе этого объекта до тех пор, пока другой поток не вызовет метод <code>notify()</code> или <code>notifyAll()</code> для этого объекта, но не дольше
     * заданного времени. Если заданное время ожидания равно нулю, то ожидание будет длиться до тех пор, пока другой поток не вызовет метод <code>notify()</code> или <code>notifyAll()</code> для этого объекта.
     *
     * Данный метод позволяет задать время ожидания с точностью до наносекунды. Время ожидания имеет величину (1000000 × <code>timeInMillis</code> + <code>timeInNanos</code>) наносекунд.
     * Однако далеко не все операционные системы и аппаратные возможности позволяют измерять время с точностью до наносекунды. Поэтому реальное время ожидания может быть округлено до миллисекунд.
     *
     * Текущий поток исполнения должен владеть монитором этого объекта. Поток перестаёт быть владельцем монитора, уходит в спячку, а после пробуждения — снова становится владельцем этого монитора,
     * после чего метод <code>wait</code> возвращает управление. О том, как поток исполнения становится владельцем монитора, можно узнать в описании метода <code>notify()</code>.
     * @param timeInMillis время ожидания в миллисекундах.
     * @param timeInNanos дополнительное время ожидания в наносекундах. Если и <code>timeInMillis</code>, и <code>timeInNanos</code> оба равны нулю, то оба этих аргумента игнорируются.
     * @throws IllegalArgumentException если <code>timeInMillis</code> отрицательный.
     * @throws IllegalArgumentException если <code>timeInNanos</code> отрицательный или больше 999999.
     * @throws IllegalMonitorStateException если текущий поток исполнения не владеет монитором этого объекта.
     * @throws InterruptedException если текущий поток исполнения был прерван. <em>Статус прерывания</em> сбрасывается после того, как текущий поток исполнения станет владельцем монитора этого объекта,
     * и перед тем, как это исключение будет возбуждено.
     * @see #notify()
     * @see #wait()
     * @see #wait(long)
     */
    public final void wait(long timeInMillis, int timeInNanos) throws InterruptedException {
        if(timeInMillis < 0L)
        {
            throw new IllegalArgumentException("аргумент timeInMillis не может быть отрицательным");
        }
        if(timeInNanos < 0 || timeInNanos > 999999)
        {
            throw new IllegalArgumentException("аргумент timeInNanos выходит из диапазона");
        }
        Monitor monitor = fldMonitor;
        if(monitor == null)
        {
            throw new IllegalMonitorStateException("текущий поток исполнения не владеет этим монитором");
        }
        monitor.wait(timeInMillis, timeInNanos, Thread.current().waitableHandler);
    }

    /**
     * Возвращает настоящий класс этого объекта. Этот объект типа <code>Class</code> используется в качестве монитора в статичных синхронизированных (<code>static synchronized</code>) методах этого класса.
     * @return объект типа <code>Class</code>, представляющий настоящий класс этого объекта.
     */
    public final native Class getClass();

    /**
     * Автоматически вызывается сразу после того, как конструктор вернул управление. Компилятор ПВТ-ОО вставляет инструкцию вызова этого метода после каждой инструкции вызова конструктора в операторах
     * <code>new</code>.
     * Допустим, что написана строка кода:
     *
     * <code>Vector v = new Vector(15);</code>
     *
     * Компилятор ПВТ-ОО сгенерирует для неё следующие инструкции:
     * </p><ol><li>
     * Создать пустую инстанцию класса <code>Vector</code>.
     * </li><li>
     * Передать <code>int</code> 15 конструктору в качестве аргумента.
     * </li><li>
     * Вызвать конструктор <code>Vector(int)</code> для созданной пустой инстанции. После возврата из конструктора инстанция считается проинициализированной.
     * </li><li>
     * Вызвать метод <code>afterConstruction()</code> для этой инстанции.
     * </li><li>
     * Присвоить ссылку на эту инстанцию переменной <code>v</code>.
     * </li></ol><p>
     * Таким образом, код внутри переопределённого <code>afterConstruction()</code> выполняется для только что созданного и полностью проинициализированного объекта.
     *
     * Для массивов этот метод не вызывается, поскольку массивы в ПВТ-ОО имеют иной механизм инициализации.
     *
     * Реализация данного метода в классе <code>Object</code> не делет чего-либо и сразу же возвращает управление.
     * @see #beforeDestruction()
     */
    protected void afterConstruction() {  }

    /**
     * Вызывается автоматическим сборщиком мусора перед утилизацией этого объекта. Если автоматический сборщик мусора видит, что этот объект больше не используется программой, то вызовет для него метод
     * <code>beforeDestruction()</code> и отметит выделенную под него память как свободную. Переопределение этого метода необходимо для освобождения ресурсов, созданных системными библиотеками опреационной системы
     * и требующих явного удаления из памяти.
     *
     * При переопределении данного метода следует помнить о том, что этот объект будет утилизирован после возврата управления, поэтому коду внутри переопределённого <code>beforeDestruction()</code> не следует
     * сохранять где-либо ссылку на этот объект, иначе неизбежны ошибки в работе программы. Любые исключения, возбужденные этим методом, игнорируются автоматическим сборщиком мусора.
     *
     * Для массивов этот метод не вызывается, поскольку массивы в ПВТ-ОО имеют иной механизм инициализации.
     *
     * Реализация данного метода в классе <code>Object</code> не делет чего-либо и сразу же возвращает управление.
     * @see #afterConstruction()
     */
    protected void beforeDestruction() {  }

    package final void checkObjectArrayAssignable(Object element) {
        Class saving;
        Class required = getClass().componentType;
        if(required == null || (required.modifiers & (Class.INTERFACE | Class.PRIMITIVE)) == Class.PRIMITIVE)
        {
            throw new VerifyError("ожидался массив объектных ссылок");
        }
        if(element != null && !required.isAssignableFrom(saving = element.getClass()))
        {
            throw new ArrayStoreException("сохранение в массиве данных иного типа невозможно") { saving = saving, required = required };
        }
    }

    package final Monitor monitor { read = fldMonitor }

    private void lock() {
        Monitor monitor = fldMonitor;
        if(monitor == null)
        {
            Mutex sysmutex = Runtime.getInstance().systemMutex;
            sysmutex.lock();
            try
            {
                if((monitor = fldMonitor) == null) fldMonitor = monitor = new Monitor();
            }
            finally
            {
                sysmutex.unlock();
            }
        }
        monitor.lock();
    }

    private void unlock() {
        Monitor monitor = fldMonitor;
        if(monitor == null)
        {
            throw new IllegalMonitorStateException("текущий поток исполнения не владеет этим монитором");
        }
        monitor.unlock();
    }
}