各锁的理解

导读:本篇文章讲解 各锁的理解,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

1:公平锁,非公平锁;

公平锁:非常的公平,不能够插队,必须先来厚道。
非公平锁:非常的不公平,可以插队,(默认都是非公平的)

查看底层ReentrantLock 的底层实现,可以自己设置公平锁,和非公平锁;
我们可以看到 ReentrantLock 有一个参数是bollean ,是指为 true 表示获得了公平锁;默认的非公平锁;

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

//可以自己设置;
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

2:可重入锁;

在这里插入图片描述
Syschronized版

package com.baidu.Lock;

/**
 * 一个同步方法可以调用另外一个同步方法,一个线程己经拥有某个对象的锁,
 * 再次申请的时候仍然会得到该对象的锁	也就是说synchronized获得的锁是可重入的
 *
 * synchronized是可重入锁,可以粗浅地理解为同一个线程在已经持有该锁的情况下,
 * 可以再次获取锁,并且会在某个状态量上做+1操作
 *
 */

import java.util.concurrent.TimeUnit;

//可重入锁;
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");
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        call();
    }
    public synchronized void call(){
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"==>call");

    }
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/edb9f1ed1ac641c590b03079152351c2.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQmVlbiBEb2luZw==,size_20,color_FFFFFF,t_70,g_se,x_16)

Lock版

package com.baidu.Lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockDemo02 {

    public static void main(String[] args) {
        Phone2 phone = new Phone2();

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

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

class Phone2{
    //这就是一把锁,锁的就是ReentrantLock这个对象,ReenTrantLock中有AQS,AQS可以判断两次lock方法都是同一个线程,这才是可重入锁

    Lock lock = new ReentrantLock();

    public void msg(){

        lock.lock(); //lock锁必须配对;否则会死在里面;
        try {
            System.out.println(Thread.currentThread().getName()+"==>msg");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            call();  //这里也是又锁的;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }


    }
    public synchronized void call(){
        lock.lock();

        try {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"==>call");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }


    }
}

3:自旋锁

https://blog.csdn.net/qq_39004307/article/details/102550520

什么是自旋锁:
是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
自旋锁存在的问题:

  • 如果某个线程持有锁的时间过长,就会导致其它等待获取锁的线程进入循环等待,消耗CPU。使用不当会造成CPU使用率极高
  • 上面Java实现的自旋锁不是公平的,即无法满足等待时间最长的线程优先获取锁。不公平的锁就会存在“线程饥饿”问题。

优点:

  • 自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快
  • 非自旋锁在获取不到锁的时候会进入阻塞状态,从而进入内核态,当获取到锁的时候需要从内核态恢复,需要线程上下文切换。 (线程被阻塞后便进入内核(Linux)调度状态,这个会导致系统在用户态与内核态之间来回切换,严重影响锁的性能)

在这里插入图片描述

package com.baidu.Lock;

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

//自己创建一个自旋锁;
// T1获得琐,T2自旋一直尝试获得。T1解锁后,T2才可以获得琐结束自旋,然后解锁
public class SpinLockDemo {

    //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 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(1);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                spinLockDemo.myUnLock();
            }
        },"t2").start();



    }

}

测试结果: 分析:

T1获得琐,T2自旋一直尝试获得。T1解锁后,T2才可以获得琐结束自旋,然后解锁。
自旋锁的底层也是也是用的CAS 操作,
在这里插入图片描述

4:死锁

package com.baidu.Lock;

import sun.java2d.loops.TransformHelper;

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+"==>get"+lockB);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (lockB){
                System.out.println(Thread.currentThread().getName()+"Lock:"+lockB+"==>get"+lockA);

            }
        }

    }
}

解决方法:
使用 jps -l
在这里插入图片描述

使用jstack 加上进程号(4524)
在这里插入图片描述
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/71864.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!