Java教程

Java JUC并发之对于各种锁的理解以及如何解决死锁问题

本文主要是介绍Java JUC并发之对于各种锁的理解以及如何解决死锁问题,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

对于各种锁的理解

  1. 公平锁、非公平锁

    公平锁 : 不允许插队,必须先来后到

    非公平锁: 允许插队(默认都是非公平锁)

  2. 可重入锁

    synchronized 这里是同一把锁

    package com.liu.lock8.reentrantLock;
    
    public class Demo01 {
    
        public static void main(String[] args) {
    
            Phone phone = new Phone();
            new Thread(()->{
                phone.sendMsg();
            },"A").start();
    
            new Thread(()->{
                phone.sendMsg();
            },"B").start();
        }
    }
    
    class Phone{
    
        public synchronized void sendMsg() {
            System.out.println(Thread.currentThread().getName() + " => sendMsg()");
            call();  // 这里也有锁
        }
    
        public synchronized void call() {
            System.out.println(Thread.currentThread().getName() + " => call()");
        }
    }
    

    lock 这里是两把不同的锁

    package com.liu.lock8.reentrantLock;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Demo02 {
    
        public static void main(String[] args) {
    
            Phone02 phone = new Phone02();
            new Thread(()->{
                phone.sendMsg();
            },"A").start();
    
            new Thread(()->{
                phone.sendMsg();
            },"B").start();
        }
    }
    
    class Phone02{
    
        Lock lock = new ReentrantLock();
    
        public  void sendMsg() {
    
            lock.lock(); // 一共有两把锁
            // lock锁必须配对,否则会死锁
    
            try {
                System.out.println(Thread.currentThread().getName() + " => sendMsg()");
                call();  // 这里也有锁
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public  void call() {
            lock.lock();
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " => call()");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
    

    可重入锁(递归锁)=> 可以递归调用和嵌套

    • 拿到外面的多之后,就可以自动获得里面的锁
    • lock锁必须配对,否则会导致死锁
  3. 自旋锁 spinlock

自己写一个自旋锁

package com.liu.lock8.spinlock;

import java.util.concurrent.atomic.AtomicReference;

/**
 * 自旋锁
 */
public class SpinlockDemo {

    AtomicReference<Thread> atomicReference = new AtomicReference<>();

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

            System.out.println(Thread.currentThread().getName() + "自旋中");
        }
    }

    // 解锁
    public void myUnLock() {
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName() + " ==> myUnlock");

        atomicReference.compareAndSet(thread, null);
    }
}

运行结果: 线程T1先获得自旋锁,T1进入休眠状态,之后线程T2获得自旋锁,而T2一直在自旋,直到T1休眠结束,释放锁,线程T2才停止自旋并解锁。

  1. 死锁

    什么是死锁?

    模拟死锁:

package com.liu.lock8.deadlock;

import java.util.concurrent.TimeUnit;

public class DeadLockDemo {

    public static void main(String[] args) {
        String lockA = "lockA";
        String lockB = "lockB";

        new Thread(new MyThread(lockA,lockB),"T1").start();
        new Thread(new MyThread(lockB,lockA),"T2").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() + " lock: " + lockA +",try to get "+lockB);

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (lockB) {
                System.out.println(Thread.currentThread().getName() + "lock: " + lockB +  ",try to get " + lockA);
            }
        }
    }
}

运行结果: T1获取到了lockA,但是同时想要拿到lockB;

​ T2获取到了lockB,但是同时想要拿到lockA;

两个线程一直在等待对方释放锁,线程无法停止下来,于是便会导致死锁!

解决死锁办法 在IDEA终端上可以使用这些命令排查问题

  1. 使用 jps -l查询运行的进程号

  1. 使用 jstack 进程号 => 查看死锁信息

面试: 工作中如何排查问题(死锁)

  1. 日志
  2. 堆栈 jstack
这篇关于Java JUC并发之对于各种锁的理解以及如何解决死锁问题的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!