18、各种锁的理解(非公平锁和公平锁、可重入锁、自旋锁、死锁)

非公平锁和公平锁

非公平锁:非常不公平的锁,效率高!(Lock和synchronized 默认是这个锁)

公平锁:非常公平的锁,遵循先来后到的原则!

比如:有两个线程耗时 3h 3s,公平锁回去等待3h后在执行3s

非公平锁会直接执行3s

怎么创建呢?

public ReentrantLock() {    // 默认非公平锁
    sync = new NonfairSync();
}

public ReentrantLock(boolean fair) {    // 设置为true,就是公平锁
    sync = fair ? new FairSync() : new NonfairSync();
}

可重入锁

可重入锁(也叫递归锁)

介绍

 代码测试

synchronized版

package com.zxh.lock;

public class Demo01 {
    public static void main(String[] args) {
        Phone phone = new Phone();

        new Thread(()->{
            phone.msg();
        }, "A").start();
        new Thread(()->{
            phone.msg();
        }, "B").start();

    }
}
class Phone{

    public synchronized void msg(){
        System.out.println(Thread.currentThread().getName() + " msg()");
        call();
    }

    public  synchronized void call(){
        System.out.println(Thread.currentThread().getName() + "call()");
    }
}

Lock版

package com.zxh.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.msg();
        }, "A").start();
        new Thread(()->{
            phone.msg();
        }, "B").start();

    }
}
class Phone2{
    Lock lock = new ReentrantLock();

    // 可重入锁,拿到msg的锁,相对的就拿到了call的锁
    public void msg(){
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " msg()");
            call();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void call(){
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "call()");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

自旋锁

CAS底层就是调用自旋锁

自定义自旋锁

package com.zxh.lock;

import org.omg.CORBA.TIMEOUT;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

public class SpinLock {

    // Thread泛型,内存中的默认值为null
    private AtomicReference<Thread> atomicReference = new AtomicReference();

    // 自定义加锁方法
    public void mylock(){
        boolean flag;
        Thread thread = Thread.currentThread(); // 获取调用该锁的线程
        System.out.println(thread.getName() + "=> mylock");

        // 自旋锁定义,如果我们期望 当前的原子引用的值为null,就修改为当前线程thread
        /*
            线程A和B用的是同一把锁
            A进入,atomicReference.compareAndSet(null, thread),因为一开始为null,所以替换内存中值为A线程
                替换成功返回true,没有进入循环
            B进入,atomicReference.compareAndSet(null, thread),因为已经有了A进程的值
                所以替换失败返回false,进入死循环
            需要等到A线程解锁,调用atomicReference.compareAndSet(thread, null);方法,将值设置null
            B线程才可以停止循环,再执行解锁操作
          */
        while(!atomicReference.compareAndSet(null, thread)){

        }
    }

    // 自定义解锁方法
    public void myunlock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName() + "=> myunlock");

        // 将当前的原子引用的值(内存中的值)修改为null
        // 因为修改为null之后,mylock方法中的 compareAndSet方法就会修改成功
        atomicReference.compareAndSet(thread, null);
    }

}

测试代码

package com.zxh.lock;

import java.util.concurrent.TimeUnit;

public class TestSpinLock {
    public static void main(String[] args) throws InterruptedException {
        SpinLock spinLock = new SpinLock();

        new Thread(()->{
            spinLock.mylock();

            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            spinLock.myunlock();
        },"A").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
            spinLock.mylock();

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            spinLock.myunlock();
        },"B").start();


    }
}

死锁

为什么会发生死锁?

比如:两个线程互相抢夺对方的资源

死锁测试,怎么排除死锁:

package com.zxh.lock;

import java.util.concurrent.TimeUnit;

public class DeadLockDemo {
    public static void main(String[] args) {
        String lockA = "苹果";
        String lockB = "蛋糕";

        new Thread(new MyThread(lockA, lockB), "A").start();
        new Thread(new MyThread(lockB, lockA), "B").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 + " 又想要 " + lockB);

            synchronized (lockB){
                System.out.println(Thread.currentThread().getName() + "=> " + lockB + "又想要 " + lockA);

            }

        }
    }
}

因为死锁没有输出,如何排错?

1、使用jps -l定位正在运行的进程号

 

2、使用jstack 进程号找到死锁问题

 

 

 面试,工作中! 排查问题:通过 1、日志 2、堆栈信息

 

posted @ 2020-06-02 16:13  忘忧山的兰木  阅读(530)  评论(0编辑  收藏  举报
她只是想吃这个而已啊……这一定是她非常爱吃的,我居然连如此细微的幸福也夺走了……
Hide
Switch
Save