Arte Java programación concurrente (12) cerraduras y bloqueos de escritura de reentrada

cerradura de reentrada

ReentrantLock bloqueo reentrante, lo que indica que la cerradura es capaz de soportar una duplicación de bloqueo hilo de los recursos. El apoyo a la selección justo y al injusto bloqueo.
sincronizada apoyo reingreso implícita palabra clave, como una modificación sincronizada del método recursivo, cuando el método de ejecución, hilos de ejecución todavía varias veces para obtener el bloqueo después de adquirir la cerradura.
Aunque no es capaz de ReentrantLock como un apoyo implícito de re-entrada, al igual que la palabra clave sincronizada, pero cuando se llama al método de bloqueo (), ha sido adquirido para bloquear el hilo puede llamar a la cerradura de nuevo () para obtener el bloqueo sin ser bloqueado.

Implementar el reingreso

Re-entrada se refiere a cualquier hilo puede adquirir el bloqueo de nuevo después de la adquisición de bloqueo para bloquear sin ser bloqueado.
(1) hilo adquiere el bloqueo de nuevo . cerradura necesidad de identificar si el hilo para adquirir el bloqueo de la cerradura hilo actual ocupado, y si es así, adquirió con éxito de nuevo.
(2) bloquear la versión final . N Repetir este hilo adquirido el bloqueo, entonces el n-ésimo de liberación de la cerradura, otros hilos pueden obtener la cerradura. La solicitud de adquisición de bloqueo final para liberar el bloqueo de la automultiplicadoras contado, el recuento representa el momento actual se repite bloqueo adquirido, y cuando se libera el bloqueo, disminuir el recuento cuando el recuento es igual a 0 indica que el bloqueo ha sido lanzado con éxito.

		非公平性(默认)
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {              
                if (compareAndSetState(0, acquires)) {    CAS设置同步状态,即获取锁
                    setExclusiveOwnerThread(current);     记录当前线程
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {如果是获取锁的线程再次请求,则将同步状态值进行增加并返回 true,表示获取同步状态成功。
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;           
            if (Thread.currentThread() != getExclusiveOwnerThread())    判断当前线程是否为获得锁的线程     
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {                          最终释放条件c=0
                free = true;
                setExclusiveOwnerThread(null);     清空获得锁的线程
            }
            setState(c);
            return free;           如果该锁被获取锁被获取了n次,那么前(n-1)次都返回false,只有同步状态完全被释放,才返回true
        }

Justo y el acceso equitativo a la diferencia entre la no-bloqueo

La imparcialidad o no es para el orden cronológico absoluto en términos de adquisición de la cerradura, si una cerradura es justo, entonces el fin de obtener el bloqueo debe estar en línea con la solicitud, que es FIFO

        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&   加入了同步队列中当前节点是否有前驱节点的判断
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;        有线程比当前线程更早地请求获取锁,因此需要等待前驱线程获取并释 放锁之后才能继续获取锁。
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

Este método nonfairTryAcquire (adquiere INT) la comparación, la única diferencia de determinación de la posición condiciones más hasQueuedPredecessors () método, es decir, añadido se determina si la cola síncrono en el nodo actual tiene un nodo predecesor, Si este método devuelve verdadero, indica que hay un hilo de el subproceso actual a principios de solicitar a adquirir el bloqueo, es necesario esperar a que un precursor de hilo para obtener y liberar el bloqueo después de cerradura para continuar recibiendo.

Bloqueo de lectura y escritura

ReadWriteLock sólo define dos métodos para obtener bloqueos de leer y escribir, que readLock () método y WriteLock método, y su aplicación ReentrantReadWriteLcok.

nombre del método descripción
int getReadLockCount () Devuelve el número de bloqueo de lectura se adquiere actual. La primera frecuencia y el número de depósitos no es igual al número de hilos de la adquisición de un bloqueo de lectura, por ejemplo, sólo un hilo, que adquiere de forma continua (reentrada) n veces leído de bloqueo, entonces el bloqueo de lectura está ocupada por 1, pero el método devuelve n
int getReadHoldCount () Devuelve el hilo actual para obtener el número de bloqueos de lectura. Se añadió este método en java6 a ReentrantReadWriteLock usando TreadLocal guardar el número del hilo actual adquirida, que también hace que la realización java6 ser más complejo
boolean isWriteLocked () La determinación de si un bloqueo de escritura se adquiere
int getWriteHoldCount () Devuelve el número de bloqueo de escritura se adquiere actual
public class Cache {
    static Map<String,Object> map=new HashMap<>();
    static ReentrantReadWriteLock readWriteLock=new ReentrantReadWriteLock();
    static Lock r=readWriteLock.readLock();
    static Lock w=readWriteLock.writeLock();
    获取一个key对应的value
    public static final Object get(String key){
        r.lock();
        try {
            return map.get(key);
        }finally {
            r.unlock();
        }
    }
    设置key对应得value,并返回旧得value
    public static final Object put(String key,String value){
        w.lock();
        try {
            return map.put(key,value);
        }finally {
            w.unlock();
        }
    }
    清空所有的内容
    public static final void  clear(){
        w.lock();
        try {
            map.clear();
        }finally {
            w.unlock();
        }
    }
}

combinación de caché de un no seguro para subprocesos como la implementación de caché HashMap, mientras que el uso de bloqueo de lectura-escritura para leer y escribir cerraduras para asegurar que la memoria caché es una caja fuerte hilo. En la operación de obtención método read (String key) para obtener un bloqueo de lectura, que permite el acceso simultáneo no se bloquea cuando el método. método de método de escritura de venta (String key, Object value) y claro (), debe obtener por adelantado por escrito al actualizar bloqueo HashMap, después de obtener un bloqueo de escritura, otros hilos para obtener bloqueos de lectura y escritura para se bloquean, y sólo escritura después de que el bloqueo se libera, las otras operaciones de lectura y escritura para continuar. usos caché concurrencia de actualización de bloqueo de lectura y escritura, sino también para garantizar la visibilidad de cada operación de escritura para todas las operaciones de lectura y escritura, al tiempo que simplifica la programación.

Lea y bloqueo de escritura análisis

El diseño de lectura-escritura, la adquisición de bloqueo de escritura y la liberación, obtener y liberar el bloqueo y leer rebaja de bloqueo

Diseñado para leer y escribir Estado

sincronizador de bloqueo de escritura también se basan función personalizada para lograr la sincronización, el estado síncrono de la misma es sincronizador de lectura-escritura.
Si el estado de mantenimiento de una pluralidad de variable entera, debe necesitar "corte usando bit a bit" variables, la variable de corte bloqueo de escritura en dos porciones, los 16 bits superiores representan leer, escribir los 16 bits más bajos representan.
Aquí Insertar imagen Descripción
Estado de sincronización actual representa un hilo ha adquirido un bloqueo de escritura, y volvió a entrar dos veces, la sincronización también está adquiriendo dos bloqueo de lectura consecutiva.
Por operaciones de bits, lectura y escritura para determinar los estados respectivos.
Supongamos que el valor actual de los bits de estado de sincronización S, el estado de escritura es igual a S & 0x0000FFFF (mayor a borrar la totalidad de 16 bits), un estado de lectura es igual a S >>> (0 complemento sin signo de 16 bits desplazamiento a la derecha).
Cuando un estado aumenta de escritura, igual a S + 1, se incrementa en 1 cuando el estado de lectura, es igual a S + (1 << 16), es decir, S + 0x00010000
de acuerdo con un estado dividido puede sacar conclusiones: S no es igual a 0, cuando estado de escritura (S & 0x0000FFFF) es igual a 0, el estado a continuación, leer (S >>> 16) es mayor que 0, es decir, el bloqueo de lectura ha sido adquirida.

adquisición de bloqueo de escritura y la liberación

bloqueo de escritura es un soporte reingreso de un bloqueo exclusivo. Si el subproceso actual ha adquirido un bloqueo de escritura, aumentar el estado de escritura. Si el hilo actual, mientras que la adquisición de bloqueos de escritura, bloqueo de lectura ha sido adquirida (estado de lectura no es 0) o el hilo no es ya obtener el hilo de bloqueo de escritura, el hilo actual en un estado de espera.

        protected final boolean tryAcquire(int acquires) {
            /*
             * Walkthrough:
             * 1. If read count nonzero or write count nonzero
             *    and owner is a different thread, fail.
             * 2. If count would saturate, fail. (This can only
             *    happen if count is already nonzero.)
             * 3. Otherwise, this thread is eligible for lock if
             *    it is either a reentrant acquire or
             *    queue policy allows it. If so, update state
             *    and set owner.
             */
            Thread current = Thread.currentThread();
            int c = getState();
            int w = exclusiveCount(c);
            if (c != 0) {    存在读锁或者当前线程不是已经获取写锁的线程,如果存在读锁,则写锁不能被获取,原因在于:读写锁要确保写锁的操作读读锁可见,如果允许读锁在已被获取的情况下对写锁的获取,那么正在运行的其他读线程就无法感知到当前写线程的操作。
            因此,只有等待其他读线程都释放了读锁,写锁才能被当前线程获取,而写 锁一旦被获取,则其他读写线程的后续访问均被阻塞。
                // (Note: if c != 0 and w == 0 then shared count != 0)
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // Reentrant acquire
                setState(c + acquires);
                return true;
            }
            if (writerShouldBlock() ||
                !compareAndSetState(c, c + acquires))
                return false;
            setExclusiveOwnerThread(current);
            return true;
        }
Leer adquisición de bloqueo y liberación

Leer cierre es un bloqueo compartido en el apoyo de reentrada, que pueden ser adquiridos simultáneamente por varios subprocesos, cuando no hay otros escritores de acceder (o estado de escritura es 0), bloqueo de leer siempre fue adquirido con éxito, y sólo hizo (thread-safe) aumentar el estado de lectura. Si el subproceso actual ha adquirido un bloqueo de lectura, mejorar el estado de lectura. Si el hilo actual, mientras que la adquisición de un bloqueo de lectura, bloqueo de escritura ha sido adquirido por otro hilo, a continuación, en un estado de espera.

        protected final int tryAcquireShared(int unused) {
            /*
             * Walkthrough:
             * 1. If write lock held by another thread, fail.
             * 2. Otherwise, this thread is eligible for
             *    lock wrt state, so ask if it should block
             *    because of queue policy. If not, try
             *    to grant by CASing state and updating count.
             *    Note that step does not check for reentrant
             *    acquires, which is postponed to full version
             *    to avoid having to check hold count in
             *    the more typical non-reentrant case.
             * 3. If step 2 fails either because thread
             *    apparently not eligible or CAS fails or count
             *    saturated, chain to version with full retry loop.
             */
            Thread current = Thread.currentThread();
            int c = getState();
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)
                return -1;
            int r = sharedCount(c);
            if (!readerShouldBlock() &&
                r < MAX_COUNT &&
                compareAndSetState(c, c + SHARED_UNIT)) {
                if (r == 0) {
                    firstReader = current;
                    firstReaderHoldCount = 1;
                } else if (firstReader == current) {
                    firstReaderHoldCount++;
                } else {
                    HoldCounter rh = cachedHoldCounter;
                    if (rh == null || rh.tid != getThreadId(current))
                        cachedHoldCounter = rh = readHolds.get();
                    else if (rh.count == 0)
                        readHolds.set(rh);
                    rh.count++;
                }
                return 1;
            }
            return fullTryAcquireShared(current);
        }

En el método tryAcquireShared (int sin usar), si otro hilo ya ha adquirido bloqueo de escritura, entonces el hilo actual para adquirir un bloqueo de lectura no pudo entrar en el estado de espera. Si el subproceso actual para obtener un bloqueo de escritura o lectura de bloqueo no se adquiere, el subproceso actual (thread-safe, confiando en la garantía CAS) para aumentar el estado de lectura, adquirió con éxito un bloqueo de lectura. Lea cada liberación de bloqueo (thread-safe, puede haber múltiples hilos leen simultáneamente la liberación bloqueo de lectura) se redujeron estado de lectura, lo que reduce el valor de (1 << 16).

rebaja de bloqueo

rebaja de bloqueo se refiere a la rebaja de bloqueo de escritura convertido en un bloqueo de lectura. Si el hilo actual posee el bloqueo de escritura y soltarlo luego, y finalmente adquirir un bloqueo de lectura, este proceso no puede ser llamado para completar la rebaja de bloqueo segmento. medios de bloqueo de downgrade a celebrar en (propiedad actualmente) bloqueos de escritura, y después de obtener un bloqueo de lectura, entonces el proceso (anteriormente propiedad) liberar bloqueo de escritura.

Publicado 24 artículos originales · ganado elogios 1 · visitas 538

Supongo que te gusta

Origin blog.csdn.net/qq_45366515/article/details/105244806
Recomendado
Clasificación