Fair locks, unfair locks, reentrant locks, and deadlocks in multithreading [detailed summary]

fair lock

Multiple threads acquire locks in the order in which they apply for locks, and the threads will directly enter the queue to queue, and will always be the first in the queue to acquire locks. The efficiency is relatively low, but the utilization of cpu is high

unfair lock

When multiple threads go to acquire the lock, they will try to acquire it directly. If they cannot acquire it, they will enter the queue and wait in the queue. If they acquire the lock, they will directly acquire it. High efficiency, but the thread is easy to starve to death (all the work is done by one thread)

Usage of fair locks and unfair locks

When creating a reentrant lock, pass true into the constructor

private final ReentrantLock lock = new ReentrantLock(true);

Why can it be created like this, let's take a look at the source code of ReentrantLock

// 在没有传入参数时,默认创建一个非公平锁
public ReentrantLock() {
    
    
    sync = new NonfairSync();
}
// 当传入一个true值时,为公平锁
public ReentrantLock(boolean fair) {
    
    
    sync = fair ? new FairSync() : new NonfairSync();
}

reentrant lock

It refers to the unit of thread. When a thread acquires the object lock, the thread can acquire the object lock again, while other threads cannot. Both synchronized and ReentrantLock are reentrant locks.

  • sychronized is an implicit lock that does not need to be locked and unlocked manually, while lock is an explicit lock that needs to be locked and unlocked manually
  • Reentrant locks are also called recursive locks

Synchronized reentrant lock example

/**
 * 演示可重入锁是什么意思,可重入,就是可以重复获取相同的锁而不会出现死锁
 * synchronized和ReentrantLock都是可重入的
 * */
public class WhatReentrantSynchronized {
    
    
    // 创建一个锁对象
    static Object mylock = new Object();
    public static void main(String[] args) {
    
    
        new Thread(()->{
    
    
            // 创建第一个锁
            synchronized (mylock){
    
    
                System.out.println("这是第一层锁");
                synchronized (mylock){
    
    
                    System.out.println("这是第二层锁");
                }
            }
        }).start();
    }
}

Sample code for ReentrantLock

/**
 * lock和unlock的数量必须一致,否则会出现死锁
 * */
public class WhatReentrantLock {
    
    
    public static void main(String[] args) {
    
    
        ReentrantLock lock = new ReentrantLock();
        new Thread(()->{
    
    
            // 上锁
            lock.lock();
            try {
    
    
                System.out.println("这是第一层锁");
                // 再次上锁
                lock.lock();
                try{
    
    
                    System.out.println("这是第二层锁");
                }finally {
    
    
                    lock.unlock();
                }
            }finally {
    
    
                lock.unlock();
            }
        }).start();
    }
}

deadlock

A deadlock is a phenomenon in which two or more transactions occupy each other on the same resource and request to lock each other's resources, resulting in a vicious circle.

When multiple processes are in a deadlock (waiting for each other) due to competition for resources, these processes will not be able to move forward without external force. This situation is a deadlock.

Obviously, if there is no external force, each process involved in the deadlock will always be in a blocked state.

Please add a picture description

Cause of deadlock

  • Insufficient system resources
  • Improper allocation of system resources
  • Processes running out of order

Commonly used methods to solve deadlocks

  • If different programs will access multiple tables concurrently, try to agree to access the tables in the same order, which can greatly reduce the chance of deadlock.

  • In the same transaction, try to lock all the resources needed at one time to reduce the probability of deadlock.

  • For business parts that are very prone to deadlocks, you can try to use upgraded locking granularity to reduce the probability of deadlocks through table-level locking.

  • If the business processing is not good, you can use distributed transaction locks or optimistic locks.

Determine if a program is deadlocked

  • jps is similar to ps -ef in linux to view the process number
  • The stack trace tool that comes with jstack

The case of deadlock (interview will ask)

public class DeadLock {
    
    
 
    //创建两个对象
    static Object a = new Object();
    static Object b = new Object();
 
    public static void main(String[] args) {
    
    
        new Thread(()->{
    
    
            // 获取a这把锁
            synchronized (a) {
    
    
                System.out.println(Thread.currentThread().getName()+" 持有锁a,试图获取锁b");
                try {
    
    
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                synchronized (b) {
    
    
                    System.out.println(Thread.currentThread().getName()+" 获取锁b");
                }
            }
        },"A").start();
 
        new Thread(()->{
    
    
            // 获取b这把锁
            synchronized (b) {
    
    
                System.out.println(Thread.currentThread().getName()+" 持有锁b,试图获取锁a");
                try {
    
    
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                synchronized (a) {
    
    
                    System.out.println(Thread.currentThread().getName()+" 获取锁a");
                }
            }
        },"B").start();
    }
}

Guess you like

Origin blog.csdn.net/weixin_54046648/article/details/128182779