Funciones y uso sincronizados

1. Características

1.1 Exclusión Mutua (Ininterrumpibilidad)

  • Al ingresar el bloque de código modificado sincronizado, es equivalente a obtener el bloqueo, llamar加锁
  • Cuando se sale del bloque de código modificado sincronizado, es equivalente a liberar el bloqueo, llamado解锁

Cuando un hilo ya ha adquirido el bloqueo, otros hilos también ejecutan la sincronización del mismo objeto y también quieren adquirir el bloqueo para la operación de bloqueo, pero si no se puede agregar, ingresará 阻塞等待. Hasta que se desbloquee el subproceso anterior, otros subprocesos tienen la oportunidad de adquirir el bloqueo. Es solo una oportunidad. Si el bloqueo se adquiere realmente depende de la programación del sistema operativo. Sincronizado es 非公平锁, y no obedecerá al primero en llegar, primero en llegar y adquirir el candado confiar en la competencia

1.2 Visibilidad de memoria garantizada

Para obtener más información, consulte el artículo anterior [Problemas de seguridad de subprocesos]

Breve descripción del proceso de trabajo:

  1. adquirir bloqueo
  2. Copia variables compartidas de la memoria principal a 工作内存, es decir, registros
  3. ejecutar código
  4. Sincronizar variables compartidas modificadas 主内存en
  5. liberar bloqueo

Asegúrese de que cada lectura de la variable compartida se lea 主内存desde ella , para evitar la aparición de errores causados ​​por la optimización del compilador, de modo que otros subprocesos puedan ver a tiempo después de modificar la variable compartida.

1.3 Deshabilitar el reordenamiento de instrucciones

Para obtener más información, consulte el artículo anterior [Problemas de seguridad de subprocesos]

El compilador ejecutará las instrucciones del código 重排序para mejorar la eficiencia del programa mientras se asegura de que la lógica permanezca sin cambios. En condiciones de subproceso único, los resultados de dichos juicios de reordenación son correctos, pero en condiciones de subprocesos múltiples, el compilador no puede considerar tanto y es probable que ocurran errores. El uso de la synchronizedpalabra clave puede evitar que el compilador realice la optimización de reordenación de instrucciones.

1.4 Esclusas reentrantes

sincronizado Sí 可重入锁, para evitar 死锁la ocurrencia de fenómenos

Ejemplo de código:

synchronized public void func() {
    
    
    synchronized (this) {
    
    
        count++;
    }
}

Si sincronizado no es un bloqueo reentrante, si desea llamar al método func para implementar la operación de autoincremento del recuento de variables compartidas. En este momento, hay dos bloqueos y el objeto bloqueado sigue siendo el mismo, ambos son variables de conteo

  1. Cuando se llama al método func y se ingresa el sincronizado externo, se obtendrá el bloqueo y el código se ejecutará después de agregar el bloqueo.
  2. Hay otro sincronizado dentro del método, y también quiero adquirir el mismo bloqueo, pero si quiero adquirir el bloqueo anterior, el bloqueo debe liberarse después de ejecutar el método func.
  3. Sin embargo, el código envuelto en el sincronizado externo no se ha ejecutado porque quiere adquirir el bloqueo (esperando el bloqueo), y el método func no tiene forma de continuar la ejecución, y está bloqueado y bloqueado.

Sincronizado es un bloqueo reentrante, que soluciona muy bien este problema, después de todo es muy probable que ocurra al repetir la operación de bloqueo y luego escribir el código.

Cada objeto de bloqueo tiene dos piezas de información, una es cuando 前锁被哪个线程持有y la otra es 当前这个锁已经被加锁了几次, habrá un contador para registrar la cantidad de veces que el hilo adquiere el bloqueo. Cuando se ejecuta el bloque de código sincronizado, el número del contador será -1 hasta que el número del contador sea 0, suelte el bloqueo

En segundo lugar, la pregunta de la entrevista: punto muerto

En un entorno concurrente, debido a la competencia por los recursos, cada proceso espera los recursos de los demás, lo que hace que cada proceso se bloquee y no pueda avanzar “死锁”. Después de que ocurra un interbloqueo, estos procesos no podrán avanzar sin interferencia externa.

En realidad, hay varios tipos de situaciones de interbloqueo.

2.1 Un hilo, una cerradura

En el mismo hilo, el mismo bloqueo se agrega dos veces, vea el caso anterior

2.2 Dos hilos, dos cerraduras

escena:

El malo tomó al rehén y le dijo a la familia del rehén, si me dan 1 millón en efectivo, los dejaré ir, de lo contrario romperé el boleto.

Después de que los miembros de la familia tienen dinero, toman el dinero y dicen, primero déjame ir y te daré el dinero.

estancado . .

inserte la descripción de la imagen aquí

Código:

//家属实现
class GoodMan {
    
    
    public void say() {
    
    
        System.out.println("你先放人,我再给你钱!");
    }
    public void get() {
    
    
        System.out.println("解救人质成功");
    }
}
class BadMan {
    
    
    public void say() {
    
    
        System.out.println("你先给我钱,我再放人!!");
    }
    public void get() {
    
    
        System.out.println("成功拿到钱");
    }
}

Secuestrando la escena:

class Main {
    
    
    public static void main(String[] args) {
    
    
        GoodMan goodMan = new GoodMan();//好人实例
        BadMan badMan = new BadMan();//坏人实例
        Object man = new Object();//人质
        Object money = new Object();//钱
        //坏人线程
        Thread t1 = new Thread(()->{
    
    
            //坏人劫持着人质(占用人质资源不放)
           synchronized (man) {
    
    
               badMan.say();//先给我钱,我再放人
               try {
    
    
                   Thread.sleep(1000);//休眠一下,确保好人线程启动,准备好钱
               } catch (InterruptedException e) {
    
    
                   e.printStackTrace();
               }
               //想要获取钱资源,但是被好人占着不放,僵住了
               synchronized (money) {
    
    
                   badMan.say();
               }
           }
        });
        t1.start();//创建坏人线程
        Thread t2 = new Thread(()->{
    
    
            //好人准备好钱(占用钱资源不放)
            synchronized (money) {
    
    
                goodMan.say();//你丫倒是先放人,我再给你钱
                //想要获取人质资源,但是被坏人占着不放,僵住了
                synchronized (man) {
    
    
                    goodMan.say();
                }
            }
        });
        t2.start();//创建好人线程
    }
}

Resultado del código:

inserte la descripción de la imagen aquí

Roscas de 2,3 N, cerraduras M

El problema de la cena de los filósofos clásicos

escena:

Filósofos (cinco) sentados alrededor de una mesa redonda, con un plato de espaguetis en el centro de la mesa y un palillo en el centro de cada filósofo

Los filósofos comen fideos cuando no están pensando en la vida. Cuando piensan en la vida, dejan los palillos. Cuando comen fideos, primero toman los palillos con la mano izquierda y luego los palillos con la derecha.

Si un filósofo descubre que otros filósofos le han quitado uno de sus palillos para comer fideos, se quedará atascado esperando

Si todos los filósofos tienen hambre, todos recogen los palillos con la mano izquierda con un gemido. En este momento, cuando todos quieren tomar los palillos con la mano derecha, el resultado es obvio, se toman los palillos con la mano derecha. por el filósofo de la derecha.Todos los recursos de los palillos están ocupados, y todos los subprocesos del filósofo están bloqueados y en espera porque no pueden colocar los palillos en la mano derecha. . .

inserte la descripción de la imagen aquí

2.4 Condiciones de interbloqueo:

  • 互斥性: cuando un recurso ya está ocupado por un subproceso, otros subprocesos no tienen forma de obtener el recurso
  • 不可抢占: un subproceso que desea adquirir un recurso (bloqueo) no puede robar al propietario del recurso y solo puede esperar hasta que el propietario del recurso libere el bloqueo antes de tener la oportunidad de adquirir el recurso.
  • 请求和保持: El subproceso que quiere adquirir el recurso no renunciará a la propiedad del recurso actualmente en posesión
  • 循环等待: Hay un bucle de espera, el subproceso t1 ocupa el recurso solicitado por el subproceso t2, el subproceso t2 ocupa el recurso solicitado por el subproceso t3 y el subproceso t3 ocupa el recurso solicitado por el subproceso t1

2.5 Romper el punto muerto

Cuando hay múltiples subprocesos y múltiples bloqueos, la forma más fácil de romper el fenómeno de interbloqueo es破解循环等待

Por lo general, se 锁排序usa para resolver el problema de interbloqueo. Puede numerar M bloqueos. Cuando lleguen N subprocesos para adquirir el bloqueo, déjelos adquirir el bloqueo en orden de menor a mayor. Si se quita el bloqueo, solo espere. , para evitar espera cíclica

3. Cómo utilizar sincronizado

¿Cuál debe 明确bloquearse al bloquear 对象, de modo que se produzca competencia cuando varios subprocesos intenten adquirir el mismo bloqueo?

3.1 Agregar directamente a los métodos normales

public class SynchronizedDemo {
    
    
    private int count;
    public synchronized void func() {
    
    
        count++;
 	}
}

A través del objeto instanciado por la clase SynchronizedDemo, llame al método func en él, ingrese el método func para bloquear y realizar la operación de incremento automático, y desbloquee el método func

Ahora 锁作用的范围mismo 整个 func 方法, 锁作用的对象es调用 func 方法的对象

3.2 Métodos estáticos de decoración

public class SynchronizedDemo {
    
    
    public synchronized static void method() {
    
    
        
    }
}

En este punto 锁作用的范围es 整个 method 方法(静态方法), ya que los métodos estáticos pertenecen a clases y no a objetos, por lo que 作用的对象es当前类对象

3.3 Decoración de bloques de código

public class SynchronizedDemo {
    
    
    public void method() {
    
    
        synchronized (this) {
    
    

        }
    }
}

Si los paréntesis son this, significa锁的对象就是当前对象

En caso afirmativo entre paréntesis SynchronizedDemo.classindicar锁的对象就是类对象

Por supuesto, también pueden ser otros objetos, en Java, 任何一个继承自 Object 类的对象,对可以作为锁对象. La operación de bloqueo en realidad está operando una bandera en el encabezado del Objeto

¡Terminar!

Supongo que te gusta

Origin blog.csdn.net/weixin_46103589/article/details/124211622
Recomendado
Clasificación