Preguntas de entrevista-13 bloqueo

En primer lugar, hablemos de la diferencia entre sincronizar y bloquear

Ambas son cerraduras, utilizadas para controlar conflictos de concurrencia. La diferencia es que Lock es una interfaz que brinda más funciones. Además de esto, tienen las siguientes diferencias:
sincronizar automáticamente libera el bloqueo, mientras que Lock debe liberarse manualmente, y hay una excepción en el código. Hará que el código de desbloqueo no se ejecute, por lo que el bloqueo generalmente se libera en Finalmente, y la JVM ejecuta automáticamente la liberación sincronizada del bloqueo.
El bloqueo tiene el concepto de bloqueo compartido, por lo que puede establecer bloqueos de lectura y escritura para mejorar la eficiencia, pero la sincronización no puede. (Ambos son reentrantes) El
bloqueo permite que el subproceso responda a las interrupciones en el proceso de adquisición del bloqueo, mientras que la sincronización no lo hace, el subproceso esperará para siempre. El método lock.lockInterruptiblemente () dará prioridad a responder a las interrupciones, en lugar de obtener primero bloqueos como el bloqueo.
Bloquear bloquea bloques de código y sincronizar también puede bloquear métodos y clases.

Dos principios de realización sincronizados

1. JVM implementa la sincronización de métodos y la sincronización de bloques de código basándose en la entrada y salida del objeto Monitor.
La sincronización a nivel de método es implícita, es decir, no necesita ser controlada por instrucciones de bytecode, sino que se implementa en operaciones de llamada y retorno de método. La JVM puede
distinguir si un método es un método sincronizado del indicador de acceso ACC_SYNCHRONIZED en la estructura method_info en el grupo de constantes del método . Cuando se llama al método, la instrucción de llamada verificará
si el indicador de acceso ACC_SYNCHRONIZED del método está establecido. Si está establecido, el hilo de ejecución primero mantendrá el monitor (el término monitor se usa en la especificación de la máquina virtual),
y luego ejecutar el método y, finalmente, el monitor se libera cuando se completa el método (ya sea que se complete de forma normal o anormal).
2. La sincronización del bloque de código utiliza las dos instrucciones de código de bytes de monitorenter y monitorexit. Están ubicados al principio y al final del bloque de código de sincronización, respectivamente. Cuando el jvm ejecuta la instrucción monitorenter, el subproceso actual intenta adquirir la propiedad del objeto monitor. Si no está bloqueado o ya está retenido por el subproceso actual, el contador de bloqueo se establece en +1; cuando se ejecuta la instrucción monitorexit , el contador de bloqueo es -1; cuando el contador de bloqueo es 0, el bloqueo se libera. Si la adquisición del objeto de monitor falla, el subproceso entrará en un estado bloqueado hasta que otros subprocesos liberen el bloqueo.
Comprensión de varios bloqueos.

1. Cerradura justa y cerradura injusta Cerradura justa: Muy justa, no puedes saltar en la cola, ¡debes ir primero! Bloqueo injusto: muy injusto, puede saltar en la cola (el valor predeterminado es injusto) 2. Bloqueos reentrantes Bloqueos
reentrantes (bloqueos recursivos)
Inserte la descripción de la imagen aquí

Synchronized
package com.kuang.lock;
import javax.sound.midi.Soundbank;
// Synchronized
public class Demo01 {
    
    
public static void main(String[] args) {
    
    
Phone phone = new Phone();
new Thread(()->{
    
    
phone.sms();
},"A").start();
new Thread(()->{
    
    
phone.sms();
},"B").start();
}
}
class Phone{
    
    
public synchronized void sms(){
    
    
System.out.println(Thread.currentThread().getName() + "sms");
call(); // 这里也有锁
}
public synchronized void call(){
    
    
System.out.println(Thread.currentThread().getName() + "call");
}
}
Lock 版
package com.kuang.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo02 {
    
    
public static void main(String[] args) {
    
    
Phone2 phone = new Phone2();
new Thread(()->{
    
    
phone.sms();
},"A").start();
new Thread(()->{
    
    
phone.sms();
},"B").start();
}
}
class Phone2{
    
    
Lock lock = new ReentrantLock();
public void sms(){
    
    
lock.lock(); // 细节问题:lock.lock(); lock.unlock(); // lock 锁必须配对,否
则就会死在里面
lock.lock();
try {
    
    
System.out.println(Thread.currentThread().getName() + "sms");
call(); // 这里也有锁
} catch (Exception e) {
    
    
e.printStackTrace();
} finally {
    
    
lock.unlock();
lock.unlock();
}
}
public void call(){
    
    
lock.lock();
try {
    
    
System.out.println(Thread.currentThread().getName() + "call");
} catch (Exception e) {
    
    
e.printStackTrace();
} finally {
    
    
lock.unlock();
}
}
}

3.
Spinlock
Inserte la descripción de la imagen aquí

Personalizamos una prueba de
prueba de bloqueo

package com.kuang.lock;
import java.util.concurrent.atomic.AtomicReference;
* 自旋锁
*/
public class SpinlockDemo {
    
    
// int 0
// Thread null
AtomicReference<Thread> atomicReference = new AtomicReference<>();

// 加锁
public void myLock() {
    
    
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName() + "==> mylock");
// 自旋锁
while (!atomicReference.compareAndSet(null, thread)) {
    
    
}
}

// 解锁
// 加锁
public void myUnLock() {
    
    
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName() + "==> myUnlock");
atomicReference.compareAndSet(thread, null);
}
}
/**
* 锁
*/
public class asdf {
    
    
public static void main(String[] args) {
    
    
//如果用的是同一个锁 谁先获得锁 谁先用 其他线程只能等待获得锁才能向下走
Lock lock = new ReentrantLock();
// Lock lock1 = new ReentrantLock();
new Thread(()->{
    
    
lock.lock();
try {
    
    
TimeUnit.SECONDS.sleep(5);
System.out.println(Thread.currentThread().getName());
} catch (Exception e) {
    
    
e.printStackTrace();
} finally {
    
    
lock.unlock();
System.out.println("22");
}

},"t1").start();

new Thread(()->{
    
    
lock.lock();
try {
    
    
System.out.println(Thread.currentThread().getName());
} catch (Exception e) {
    
    
e.printStackTrace();
} finally {
    
    
lock.unlock();
System.out.println("33");
}

},"t2").start();
}
}
//运行结果
//t1
//t2
//33
//22

4. Punto muerto
Inserte la descripción de la imagen aquí

死锁测试,怎么排除死锁:
public class test1 {
    
    
public static void main(String[] args) {
    
    
String lockA = "A锁";
String lockB = "B锁";
new Thread(new MyThread(lockA,lockB)).start();
new Thread(new MyThread(lockB,lockA)).start();
}
}

class MyThread implements Runnable{
    
    
private String lockA;
private String lockB;

public MyThread(String lockA, String lockB) {
    
    
this.lockA = lockA;
this.lockB = lockB;
}

@Override
public void run() {
    
    
synchronized (lockA){
    
    
System.out.println(Thread.currentThread().getName()+lockA+"get->"+lockB);
try {
    
    
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
    
    
e.printStackTrace();
}
synchronized (lockB){
    
    
System.out.println(Thread.currentThread().getName()+lockB+"get->"+lockA);
}
}
}
}

Resuelva el problema 1. Use jps -l para ubicar el número de proceso

2. Utilice jstack + número de proceso para encontrar el problema del interbloqueo

¡Entrevista, en el trabajo! Resolución de problemas: 1. Registro 9 2. Pila 1

Supongo que te gusta

Origin blog.csdn.net/zyf_fly66/article/details/114085724
Recomendado
Clasificación