[Actualización] --- sincronizada bloqueo de la programación concurrente + jdk1.6 otra optimización de palabras clave sincronizada Introducción

Dirección de origen: https://github.com/nieandsun/concurrent-study.git


1 jdk1.6 Visión general de la optimización de palabras clave sincronizada

Artículo anterior " [] Programación concurrente - desde la perspectiva de las instrucciones de código de bytes para comprender los principios de la palabra clave sincronizada ", " [] Programación concurrente - además de comprender la palabra clave sincronizada desde la perspectiva de la fuente principio JVM " se ha introducido en JDK1 0.6 palabra clave sincronizado antes de que la lógica de procesamiento está 只要线程想进入sincronizado bloque 就会para ir 调用内核函数de aprovechar el bloqueo del monitor propiedad objeto asociado.

Llama a la función del núcleo cambiará cuestiones relacionadas con el modo de núcleo y modo de usuario, que consume una gran cantidad de recursos del sistema, reducir la eficiencia del proceso. Y los estudios han demostrado que en la mayoría de los casos el código se realiza alternativamente , 交替执行就不会产生并发,自然也就不会带来并发安全问题,por lo que este mecanismo jdk1.6 antes de la palabra clave sincronizada hay un cierto problema.

Doug Lea hizo ReentrantLock hecho, una buena solución a este problema, se puede ver en mi artículo, " [Programación Concurrente] - ReentrantLock Resolución 1 Fuente: procesamiento método de sincronización lógica ejecutado alternativamente ."

Debe ser porque la palabra clave sincronizada es la razón JDK palabra clave original, a la derecha, HotSpot equipo de desarrollo de la máquina virtual gastado en esta versión de jdk1.6 un gran esfuerzo para lograr una variedad de técnicas de optimización de bloqueo, incluyendo bloqueo sesgada (con prioridad de bloqueo), luz cerradura de peso medio (bloqueo Ligera), giro adaptativo (Spinning adaptativo), la eliminación de la cerradura (eliminación de bloqueo), engrosamiento de bloqueo (engrosamiento de bloqueo), etc. - "estas tecnologías están diseñadas para compartir datos de manera más eficiente entre los hilos, y la resolución de problemas de competencia, mejorando así la eficiencia del programa.


2 proceso de extensión de bloqueo sincronizado

El proceso de actualización es cerradura: sin cerradura -> bloqueo sesgada -> Bloqueo Ligero -> Bloqueo de peso pesado


2.1 Bloqueo sesgada (con prioridad de bloqueo) - lo mismo se aplica a un caso en el que el hilo se repite en el bloque de código de sincronización


2.1.1 ¿Qué es el bloqueo sesgada

sesgada de bloqueo es importante introducir el JDK 6, porque HotSpot Después de los autores del estudio encontraron que la práctica en 大多数情况下,Bloqueo no sólo la ausencia de competencia multi-roscado, y siempre obtener múltiples veces por el mismo hiloCon el fin de bloquear el hilo para conseguir un precio más bajo, la introducción de un bloqueo parcial.

bloqueo sesgada de "sesgo" es excéntrico "parcial" favoritismo "parcial", significa que la cerradura estará sesgada a favor de la primera para obtener su rosca, el ID del hilo se almacenará en el sesgo de bloqueo de la cabeza objeto, después de la Sólo es necesario comprobar el hilo entra y sale de sincronización de bloque es un bloqueo parcial, el indicador de bloqueo y ThreadID puede ser.

Pero debe ser retirada tan pronto como la competencia apareció sesgada de bloqueo múltiples hilos, por lo que la revocación salvado antes de su consumo sesgado rendimiento de bloqueo debe ser menor que el rendimiento del consumo CAS operación atómica, de lo contrario más daño que bien.


2.1.2 sesgada bloqueo longitudinal + principio de revocación

[Bloqueo]
Cuando la primera rosca para adquirir la cerradura y acceder a los bloques de sincronización, el proceso de bloqueo sesgada es la siguiente:

  • (1) Virtual Machine bandera voluntad la cabecera del objeto se establece en "01", que es el modo sesgado.
  • (2) el uso de la operación del CAS para llegar a la rosca de bloqueo de ID se registra en el objeto marca de la palabra entre los CAS si la operación tiene éxito, el futuro mantiene un bloqueo de rosca de bloqueo sesgada cada vez que se introduce el bloque de sincronización correspondiente, una máquina virtual ya no puede ser cualquier operación sincronizada, alta eficiencia sesgada de bloqueo.

En combinación con Mark Palabra (puedo ver en la entrada del blog " [] Programación concurrente - el diseño original del objeto java se puede demostrar de manera !!!") estructura de almacenamiento puede ser mejor entendido:
Aquí Insertar imagen Descripción


[Revocación]
Sesgado proceso de revocación de bloqueo es el siguiente:

  • (1) deshacer sesgado operación de bloqueo debe esperar a punto de la seguridad global (que se determina por JVM, en general, al igual que el extremo frontal del bucle, el método devuelve como puntos de seguridad)
  • (2) tiene una sesgados cuelga rosca de bloqueo, determina si el objeto está bloqueado el estado de bloqueo
  • (3) la revocación sesgada de bloqueo, sin bloqueo para recuperar (bandera es 01) o el bloqueo de peso ligero (00 banderas) del estado

[+ Cerradura esquemas proceso de revocación]
Sesgado bloqueo principio + revocación de bloqueo se puede expresar mediante la siguiente figura:
Este es el "arte de la programación concurrente de Java" en la explicación del proceso de dibujo, pintura bastante bueno, aquí traído consigo ☺☺☺.
Aquí Insertar imagen Descripción

2.1.3 sesgada de bloqueo de verificación

Después de bloqueo sesgada en Java 6 está activado por defecto, pero sólo se activa después de la aplicación se inicia unos segundos, puede utilizar -XX:BiasedLockingStartupDelay=0el parámetro de retardo de desconexión, si se determina en un modo competitivo en circunstancias normales, todas las aplicaciones de cerraduras, puede XX:-UseBiasedLocking=falsecerrar los parámetros de bloqueo parcial.

Verificación procedimientos son los siguientes:

package com.nrsc.ch1.base.jmm.syn_study.upgrade;
import org.openjdk.jol.info.ClassLayout;
public class BiasedLockingDemo {
    
    private static class MyThread extends Thread {
        //static修饰只会初始化一次
        static Object obj = new Object();

        @Override
        public void run() {
            for (int i = 0; i < 3; i++) {
                synchronized (obj) {
                    //打印锁对象的布局
                    System.out.println(ClassLayout.parseInstance(obj).toPrintable());
                }
            }
        }
    }

    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start();
    }
}
  • Para conseguir el efecto deseado, en tiempo de ejecución, la necesidad de añadir el siguiente parámetro VM '
-XX:BiasedLockingStartupDelay=0
  • Los resultados son los siguientes:

Aquí Insertar imagen Descripción

La parte verde de la antigua marca de la palabra 56 de almacenar el hilo ThreadId y Época, se puede ver los valores de 56 bits son los mismos que
la parte amarilla de la marca de la palabra tres últimos 101

Este resultado es consistente con la tabla descrita en 2.1.2.


2.1.4 Ventajas de bloqueo sesgada

bloqueo sesgada es mejorar aún más el rendimiento cuando sólo un hilo para realizar bloque de sincronización se aplica a un hilo obtener repetidamente la misma cerradura. bloqueo sesgada puede mejorar el rendimiento con sincronizado sin competencia.

También es un compensaciones de beneficios con propiedades optimizadas, es decir, que no siempre es beneficioso para ejecutar el programa, si el programa de la mayoría de las cerraduras son siempre un número de diferentes hilos de acceso tales como grupo de subprocesos que el modo de sesgo es redundante.

En JDK5 sesgada de bloqueo está desactivada por defecto, pero por el sesgo JDK6 bloqueo ha sido activado por defecto. Pero sólo se activa después de la aplicación se inicia unos segundos, puede utilizar -XX:BiasedLockingStartupDelay=0los parámetros de retardo de cierre, si se determina en un modo competitivo y todos normalmente bloquea la aplicación, por XX:-UseBiasedLocking=falseel cierre de los parámetros de bloqueo parcial.


resumen

  • principio de bloqueo sesgada:

Cuando el objeto de bloqueo es primero hilo consigue, la máquina virtual estará sujeto a la bandera de su cabeza se establece en "101", que es el modo sesgado. Al mismo tiempo, el uso de la operación del CAS para llegar a la rosca de bloqueo de ID se registra en el objeto marca de la palabra en la cerradura, si la operación CAS tiene éxito, el futuro mantiene un bloqueo de rosca de bloqueo sesgado cada vez que se introduce el bloque de sincronización relevante, las máquinas virtuales pueden ya no hay ninguna operación sincronizada, alta eficiencia sesgada de bloqueo.

  • Beneficios tienden a bloquear

bloqueo sesgada es mejorar aún más el rendimiento cuando sólo un hilo para realizar bloque de sincronización se aplica a un hilo obtener repetidamente la misma cerradura. bloqueo sesgada puede mejorar el rendimiento con sincronizado sin competencia.


Se aplica a rosca en el método de sincronización alternativo - 2,2 cerradura de peso ligero (Lightweight Locking)


2.2.1 ¿Qué es un bloqueo ligero

Ligera es el nuevo mecanismo de bloqueo de la cerradura en el JDK 6 agregó que el nombre de "ligera" es relativo al uso de los términos del monitor de bloqueo tradicionales, mecanismo de bloqueo tradicional se denomina bloqueo "peso pesado". Lo primero que hay que destacar:cerraduras ligeras no están destinados a sustituir la cerradura de peso pesado.

El propósito de introducir bloqueo ligero: en el caso de multi-hilo de bloques de sincronización realizado alternativamente, para evitar el rendimiento de arriba debido a la cerradura de peso pesado, pero si múltiples hilos entran en la región crítica, al mismo tiempo, la cerradura causará ligero expandido actualizarse cerradura de peso pesado, así que no hay una cerradura de bloqueo para ser peso pesado alternativa ligera.


2.2.2 + ligero principio de bloqueo de bloqueo revocado

[Bloqueo]
Cuando está cerrado sesgada función o múltiples hilos de bloqueo compita sesgada de bloqueo actualizado a plomo ligero para bloqueo de cierre parcial, que tratará de obtener un bloqueo ligero, los siguientes pasos:

  • (1) determina si el objeto actual hay un estado de bloqueo (código hash, 0, 01), y si es así, el primer JVM para establecer un espacio llamado las cerraduras (bloqueo de registro) en el marco de la pila del hilo actual para el almacenamiento de la cerradura Actualmente el objeto de la marca de la palabra copia (put oficial de esta copia, más un prefijo Desplazada, a saber Desplazada marca de la palabra), copie el objeto marca de la palabra a la estructura de pila bloqueo de registro, el bloqueo Reocrd en puntos por propietario al objeto actual.
  • (2) intentos de JVM para utilizar el objetivo de la operación CAS palabra de marca actualizada a punto de puntero de bloqueo de registro, si la competencia exitosa para representar la cerradura, entonces el indicador de bloqueo se convierte en 00, realizar operaciones de sincronización.
  • (3) si se determina que el objeto actual falla puntos marca de la palabra de marco de pila del subproceso actual, si es entonces el hilo actual ya ejerce en este objeto de bloqueo, la aplicación directa de los bloques de código de sincronización, de lo contrario el objeto de bloqueo sólo se ha descrito otros hilos apoderarse, a continuación, se expandieron en un bloqueo ligero necesita un bloqueo de peso pesado, el indicador de bloqueo se convierte en 10, a la espera detrás de la rosca va a entrar en el estado bloqueado.

[Revocación]
cerraduras ligeras son liberados por el CAS operación se realiza en los siguientes pasos:

  • (1) contraídos para obtener los datos almacenados en la cerradura de peso ligero de la marca de la palabra desplazada.
  • (2) llevado a cabo por la operación CAS sustituye a la actual objeto de datos de marca de la palabra, si tiene éxito, entonces el bloqueo de seguridad de éxito.
  • (3) Si la operación de sustitución CAS falla, el otro hilo intenta adquirir el bloqueo, tendrá que actualizar a un bloqueo de peso pesado de la inflación bloqueo ligero.

[+ Cerradura esquemas proceso de revocación]
Aquí todavía prestado "El arte de Java concurrencia" en la figura: ☺☺☺.
Aquí Insertar imagen Descripción


2.2.3 verificación de bloqueo Ligera

Interesado en probar yo mismo, puede obtener resultados inesperados. . .


2.2.4 beneficio bloqueo Ligera

Para el bloqueo de peso ligero, su funcionamiento se basa “对于绝大部分的锁,在整个生命周期内都是不会存在竞争的”, si la ruptura es en adición a la base exclusiva de costo, hay operación adicional CAS, por lo que en el caso de múltiples hilos de la competencia, de peso ligero de peso pesado de bloqueo de bloqueo más lento.

En el caso de rendimiento de bloqueo de peso pesado multiproceso donde los bloques de sincronización se llevan a cabo alternativamente se puede evitar debido al consumo.


2.3 Los spinlocks

Creemos que a través de los artículos anteriores de la ropa de cama que usted ya debe saber, utilice la función de bloqueo del monitor llama el parque hilos del núcleo y anular el estacionamiento, es decir, hilos parque Unpark necesidad de volver interruptor de un lado a otro del modo de usuario de la CPU y el modo de núcleo de conmutación. parque frecuente y anular el estacionamiento de la CPU como una pesada carga de trabajo, el desempeño simultáneo de estos sistemas operativos traerán mucha presión.

Al mismo tiempo, el equipo de desarrollo de la máquina virtual también señaló que en muchas aplicaciones, los datos compartiendo estado bloqueado 只会持续很短的一段时间, esta vez para activar la rosca y el bloqueo no vale la pena. Si la máquina física tiene más de un procesador que permite que dos o más hilos se ejecutan en paralelo, podemos conseguir detrás de esa solicitud de bloqueo de rosca “稍等一下”,, pero no renunciar al tiempo de ejecución del procesador, para ver si es el hilo que mantiene el bloqueo pronto liberar el bloqueo. Para hacer una espera de hilo, podemos 让线程执行一个死循环(自旋), esta técnica se conoce como bloqueos de giro. - "bloqueo de bucle se ha introducido en el JDK 1.4.2, pero está desactivada por defecto, puede utilizar -XX: + UseSpinning parámetros para abrir en el JDK 1.6 ha sido cambiado en está activado por defecto.

自旋等待不能代替阻塞Y no voy a hablar con el número de procesadores requeridos, escisión esperar en sí, aunque sin la sobrecarga de conmutación hilo, pero es ocupar el tiempo de procesador, por lo que si la cerradura está ocupada por un corto tiempo, el efecto de la espera de centrifugado va a ser muy buena, por el contrario, si el bloqueo está ocupada por un largo tiempo. A continuación, girar el hilo consumo de solamente un desperdicio de recursos del procesador, y no hacer ningún trabajo útil, pero traerá el rendimiento innecesaria. Por lo tanto, el tiempo de giro de espera debe tener un cierto límite, si el giro es superior al límite del número de bloqueo todavía no es exitosa, se debe utilizar la forma tradicional de colgar un hilo. El valor por defecto es 10 veces el número de giros, el usuario puede utilizar los parámetros -XX: PreBlockSpin al cambio.


2.4 bloqueos de giro de adaptación

En jdk1.6 también introdujo bloqueo de bucle adaptativo. medios de adaptación que el tiempo de giro ya no es fijo, pero se bloquea en un estado con un tiempo de bloqueo de bucle y el propietario está determinado por el anterior. Si un bloqueo en el mismo objeto spin-espera sólo cerraduras ganado con éxito, y el hilo de la celebración de la cerradura está en funcionamiento, la máquina virtual se piensa que esto es también muy probable que sea exitosa vuelta de nuevo, y entonces se permitirá giro esperar durante un periodo de tiempo relativamente más largo, tal como 100 ciclos. Además, si una cerradura para una vuelta rara vez tenido éxito, y que querían estar en
cuando el bloqueo será posible omitir el proceso de centrifugado, con el fin de evitar el desperdicio de recursos del procesador. Con la vuelta de adaptación, con el programa en ejecución y mejorar continuamente monitorear el desempeño de la información, la predicción estado de bloqueo de programa de máquina virtual será más preciso, la máquina virtual se hará más y más "inteligente".


3 jdk1.6 otra sincronizada optimización de palabras clave Introducción


3.1 Bloqueo de eliminación

Cerraduras de eliminación es un tiempo de compilador máquina virtual (JIT) en tiempo de ejecución, algunos requisitos del código para la sincronización, pero no se puede detectar compartir datos bloqueados para eliminar la competencia. Bloqueo eliminado de las principales basados juicio 逃逸分析de datos para apoyar todos los datos para determinar si una pieza de código en, el montón no escapará a cabo de manera que sea accesible para otros hilos, es posible tratarlos como datos sobre la pila, se consideran enhebrar privada, cerrada de forma natural sin la necesidad de sincronización. Variable es de escape, ya que requiere el uso de la máquina virtual de datos fluyen análisis para determinar, pero el programador debe ser muy claro, ¿cómo va a saber que no hay ningún caso claro también requieren la sincronización de los datos de contención que? En realidad, hay muchos medidas no son programador sincrónica añadido, la prevalencia de código sincrónico de los programas de Java puede exceder la imaginación de la mayoría de los lectores.

Por ejemplo, después de esta cadena de código muy simple de sólo tres de salida el resultado añadido, ya sea literalmente o la semántica de la fuente de programa no están sincronizados.

public class Demo01 {
    
    public static void main(String[] args) {
        contactString("aa", "bb", "cc");
    }
    public static String contactString(String s1, String s2, String s3) {
        return new StringBuffer().append(s1).append(s2).append(s3).toString();
    }
}

El append StringBuffer () es un método síncrono, es que esta es una cerradura (new StringBuilder ()). Su ámbito de aplicación descubrimiento máquina virtual dinámico está confinado dentro método concatString (). Es decir, cita new StringBuilder () objeto nunca es "escape" a concatString () método, otros hilos no pueden acceder a ella, así que mientras existen bloqueos, pero se pueden eliminar con seguridad, compilación en tiempo después de eso, este código ignorará todo sincronización ejecuta directamente.


3.2 锁 粗 de

En principio, estamos en la preparación del código siempre se recomienda limitar el alcance de bloques de sincronización lo más pequeño posible, pero sólo para la sincronización, por lo que a fin de hacer posible el número de operaciones necesarias para sincronizar más pequeño en el alcance real de los datos compartidos Si hay contención de bloqueo, que espera el bloqueo de ese hilo puede obtener el bloqueo tan pronto como sea posible.

En la mayoría de los casos, el principio de lo anterior son correctos, pero si una serie de operaciones sucesivas se repiten de bloqueo y de desbloqueo del mismo objeto, o de operación de bloqueo incluso está presente en el cuerpo del bucle, y que incluso si no existe contención hilo, con frecuencia el funcionamiento síncrono mutex también causan pérdida de rendimiento innecesaria. Por ejemplo, el código siguiente:

class Demo02 {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();
        //StringBuffer是同步方法,
        // 其实没必要每次append都去判断锁相关的内容,可以将整个for循环搞成同步的 ---> JVM的锁粗化可能会直接帮你这样弄
        for (int i = 0; i < 100; i++) {
            sb.append("aa");
        }
        System.out.println(sb.toString());
    }
}

¿Qué es el engrosamiento de bloqueo, creo que usted debe entender, dan definido de la siguiente manera:

JVM detectará una serie de operaciones pequeñas usan el mismo objeto de bloqueo, la gama de los bloques de código de sincronización ampliada, fuera de esta cadena en operación, por lo que el bloqueo sólo se puede añadir una vez.


fin

Publicados 226 artículos originales · ganado elogios 319 · vistas 530 000 +

Supongo que te gusta

Origin blog.csdn.net/nrsc272420199/article/details/105232637
Recomendado
Clasificación