ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

关于各种锁的理解

2021-05-01 19:32:13  阅读:211  来源: 互联网

标签:各种 Thread lock sms 理解 关于 自旋 new public


公平锁,非公平锁

公平锁:非常公平,不能插队,必须先来后到

//参数写为true,就表示公平锁(不写默认就是非公平锁)
public ReentrantLock(boolean fair) {
     sync = fair ? new FairSync() : new NonfairSync();
 }

非公平锁:非常不公平,允许插队,可以改变顺序(lock,synchronized默认都是非公平锁)

public ReentrantLock() {
    sync = new NonfairSync();
}

可重入锁

简单理解就是:锁里面还有一个锁。

特性:就是一个线程执行可重入锁后,释放全部锁的时候,另一个线程才能继续执行这个可重入锁。

加上A锁里面还有一把B锁。
线程甲执行完A,线程乙还不能执行A,因为A里面还有一把B锁。
甲执行完B锁就会释放B锁,然后再释放A锁,这时乙才能执行(使用lock这个过程特别明显)

通过Synchronized 锁实现

public class LockDemo {
    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");
    }
}
A=> sms
A=> call
B=> sms
B=> call

Lock 锁实现可重入锁

public class LockDemo {
    public static void main(String[] args) {
        Phone2 phone2  = new Phone2();
        new Thread(()->{
            phone2.sms();
        },"A").start();
        new Thread(()->{
            phone2.sms();
        },"B").start();
    }
}
class Phone2 {
    Lock lock = new ReentrantLock();

    public void sms() {
        lock.lock();//细节:这个两把锁,两个钥匙
//        lock 锁必须配对,否则就是死锁在里面
        try {
            System.out.println(Thread.currentThread().getName() + "=>sms");
            call();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

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

自旋锁

何谓自旋锁?它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名

自旋锁会不断的尝试,直到成功为主。

其实在Unsafe类中就有自旋锁的使用,下面的源码通过CAS和while循环就实现了自旋锁。

Unsafe类中的自旋锁

示例:自定义实现自旋锁(自旋锁是通过CAS和while循环实现的)

public class SpinlockDemo {
    //使用原子类通过CAS实现自旋锁
    // 默认
    // int 0
    //thread null
    AtomicReference<Thread> atomicReference=new AtomicReference<>();

    //加锁
    public void myLock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName()+"===> mylock");

        //自旋锁 当有一个线程A调用该方法,就将原始值null改为A thread,修改成功就结束自旋
        while (!atomicReference.compareAndSet(null,thread)){
            //System.out.println(Thread.currentThread().getName()+" ==> 自旋中~");
        }
    }


    //解锁
    public void myUnlock(){
        Thread thread=Thread.currentThread();
        System.out.println(thread.getName()+"===> myUnlock");
        atomicReference.compareAndSet(thread,null);
    }

}

public class TestSpinLock {
    public static void main(String[] args) throws InterruptedException {

        //使用CAS实现自旋锁
        SpinlockDemo spinlockDemo=new SpinlockDemo();
        new Thread(()->{
            spinlockDemo.myLock();
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                spinlockDemo.myUnlock();
            }
        },"t1").start();

        TimeUnit.SECONDS.sleep(1);


        new Thread(()->{
            spinlockDemo.myLock();
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                spinlockDemo.myUnlock();
            }
        },"t2").start();
    }
}
t1===> mylock
t2===> mylock
t1===> myUnlock
t2===> myUnlock

//从上面的结果我们看到,t1拿到锁后,一直在自旋,直到thread不等于空结束自旋。t2才能拿到锁,然后自旋,最后解锁

死锁

简单理解:A:先交货再给;B:先给钱再交货

形成死锁的条件

死锁示例

public class DeadLock {
    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+"===>get"+lockB);
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (lockB){
                System.out.println(Thread.currentThread().getName()+" lock"+lockB+"===>get"+lockA);
            }
        }
    }
}

如何排查死锁

  1. 运行程序造成死锁后,打开idea Terminal控制台。

  2. 输入使用 jps 定位进程号(jdk 目录 bin 下 :有一个 jps)

    命令: jps -l 查看所有进程号

    jps -l

  3. 使用 jstack 进程进程号找到死锁信息

推荐文章

参考教程:https://www.kuangstudy.com/

标签:各种,Thread,lock,sms,理解,关于,自旋,new,public
来源: https://www.cnblogs.com/lanxinren/p/14724629.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有