各种锁的理解

简介: 各种锁的理解
  1. 各种锁的理解

公平锁

 非常公平,不能插队,线程必须按照先来回到的规则调用

不公平锁

非常不公平,可以插队,线程可以允许后来的线程插到先来的前面

举个例子,如果线程A一秒就可以执行完,但是线程B需要一小时才能执行完,那么如果线程A排在了线    程B后面,是不合理的,所以非公平锁允许插队,保证了程序的效率

Java默认就是非公平锁

ReentrantLock就是如此,默认创建就是不公平的

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

改为公平锁,其实就是修改它的重载

Lock lock=new ReentrantLock(true);
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}

可重入锁(递归锁)

所有的锁都是可重入锁,它也叫递归锁

 拿到了最外面的锁之后,就可以拿到里面全部的锁,它是自动获得的,比如拿到了家大门的钥匙,就可以拿到各个卧室的锁

synchronized版

package com.wyh.lock;
/**
 * @program: JUC
 * @description: 重入锁(递归锁) 拿到了最外面的锁 也就自动拿到了里面的锁
 * @author: 魏一鹤
 * @createDate: 2022-03-13 21:50
 **/
// 重入锁(递归锁) 拿到了最外面的锁 也就自动拿到了里面的锁
public class Demo1 {
public static void main(String[] args){
//synchronized版重入锁
        Phone phone=new Phone();
new Thread(()->{
            phone.sendMessage();
        },"A").start();
new Thread(()->{
            phone.sendMessage();
        },"B").start();
    }
}
class Phone{
public synchronized  void sendMessage(){
        System.out.println(Thread.currentThread().getName()+"发短信");
        call();//这里也有一把锁
    }
public synchronized  void call(){
        System.out.println(Thread.currentThread().getName()+"打电话");
    }
}

A发短信

A打电话

B发短信

B打电话

    lock版

由于lock是手动版的,需要手动进行加锁解锁,不能忘记解锁,而且配的锁要成对,不然容易造成死锁问题

package com.wyh.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * @program: JUC
 * @description: 重入锁(递归锁) 拿到了最外面的锁 也就自动拿到了里面的锁
 * @author: 魏一鹤
 * @createDate: 2022-03-13 21:50
 **/
// 重入锁(递归锁) 拿到了最外面的锁 也就自动拿到了里面的锁
public class Demo2 {
public static void main(String[] args){
//lock版重入锁
        Phone2 phone=new Phone2();
new Thread(()->{
            phone.sendMessage();
        },"A").start();
new Thread(()->{
            phone.sendMessage();
        },"B").start();
    }
}
class Phone2{
//创建锁
    Lock lock=new ReentrantLock();
public   void sendMessage(){
//加锁业务代码放在try中 解锁放在finally中
        //细节:锁必须配对 必须解锁 不然就会死锁
        try {
lock.lock(); 
lock.lock();
            System.out.println(Thread.currentThread().getName()+"发短信");
            call();//这里也有一把锁
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
lock.unlock();
lock.unlock();
        }
    }
public   void call(){
//加锁业务代码放在try中 解锁放在finally中
        try {
lock.lock();
            System.out.println(Thread.currentThread().getName()+"打电话");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
lock.unlock();
        }
    }
}

A发短信

A打电话

B发短信

B打电话

自旋锁(spinLock)


image.png

自旋锁就是不断的循环遍历迭代,会不断的进行尝试,直到成功为止(达到成功的效果) while 和do while  

利用CAS操作模拟写一个自旋锁

package com.wyh.lock;
import java.util.concurrent.atomic.AtomicReference;
/**
 * @program: JUC
 * @description: 自旋锁测试
 * @author: 魏一鹤
 * @createDate: 2022-03-13 22:13
 **/
//自旋锁 不断遍历迭代 直到成功位置
public class SpinLockDemo {
//底层使用CAS完成
    AtomicReference<Thread> atomicReference=new AtomicReference<>();
//加锁
    public void myLock(){
//获取线程
        Thread thread = Thread.currentThread();
//获取线程名
        System.out.println(thread.getName()+"-------------> myLock");
//自旋锁
        while (!atomicReference.compareAndSet(null,thread)){
        }
    }
//解锁
    public void myUnLock(){
//获取线程
        Thread thread = Thread.currentThread();
//获取线程名
        System.out.println(thread.getName()+"-------------> myUnLock");
//自旋锁
        atomicReference.compareAndSet(thread,null);
    }
}

测试

package com.wyh.lock;
import java.util.concurrent.TimeUnit;
/**
 * @program: JUC
 * @description: 测试自己写的自旋锁
 * @author: 魏一鹤
 * @createDate: 2022-03-13 22:22
 **/
public class TestSpinLock {
public static void main(String[] args) throws InterruptedException {
//创建我们自己写的自旋锁 底层使用的是CAS
        SpinLockDemo lock = new SpinLockDemo();
new Thread(()->{
try {
//加锁
                lock.myLock();
//休眠
                TimeUnit.SECONDS.sleep(2);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
//解锁
                lock.myUnLock();
            }
        },"A").start();
//休眠 保证线程A先加锁
        TimeUnit.SECONDS.sleep(1);
new Thread(()->{
try {
//加锁
                lock.myLock();
//休眠
                TimeUnit.SECONDS.sleep(2);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
//解锁
                lock.myUnLock();
            }
        },"B").start();
    }
}

A-------------> myLock

B-------------> myLock

A-------------> myUnLock

B-------------> myUnLock

死锁排查

         死锁怎么造成的?

线程A持有自己的锁,线程B持有自己的锁,他们两个试图争抢对方的资源,一直僵持,就造成了死锁

package com.wyh.lock;
import lombok.SneakyThrows;
import java.util.concurrent.TimeUnit;
/**
 * @program: JUC
 * @description: 死锁测试
 * @author: 魏一鹤
 * @createDate: 2022-03-13 22:36
 **/
//死锁测试 排查死锁 其实就是两个线程互相抢别人的资源
public class DeadLockDemo {
public static void main(String[] args){
      String lockA = "lockA";
      String lockB = "lockB";
//线程A想拿线程B的锁 线程B想拿线程A的锁
      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;
    }
    @SneakyThrows
    @Override
public void run() {
synchronized (lockA) {
            System.out.println(Thread.currentThread().getName() + "lock:"+lockA+"get==>"+lockB);
//休眠2s
            TimeUnit.SECONDS.sleep(2);
synchronized (lockB) {
                System.out.println(Thread.currentThread().getName() + "lock:"+lockB+"get==>"+lockA);
            }
        }
    }
}

T1lock:lockAget==>lockB

T2lock:lockBget==>lockA

程序一直由于死锁卡着,如何解决这个问题呢?

命令排查死锁

1 使用java命令 jps -l定位进程号
2 使用jstack 进程号 查看进程信息,找到死锁原因

开发中一般都是查看日志或者堆栈信息

目录
相关文章
|
1月前
|
存储 关系型数据库 MySQL
MySQL数据库锁:共享锁和独占锁
本文详细介绍了`InnoDB`存储引擎中的两种行级别锁:共享锁(S锁)与排他锁(X锁)。通过具体示例展示了这两种锁的工作机制及其在`InnoDB`与`MyISAM`引擎中的表现差异。文章还提供了锁的兼容性矩阵,帮助读者更好地理解锁之间的互斥关系。最后总结了两种锁的特点及适用场景。适合希望深入了解`MySQL`并发控制机制的读者阅读。
41 1
|
3月前
|
SQL 关系型数据库 MySQL
MySQL使用行级锁时,并非直接锁定记录,而是锁定涉及的索引。对于表`user_item`,更新语句先锁定非主键索引`idx_1`,再锁定主键索引。若两条更新语句分别按不同顺序锁定这两个索引,可能导致互相等待对方释放锁,引发死锁。解决方案包括先查询待更新记录的主键,再按主键更新,确保一致的锁定顺序。
43 2
|
3月前
|
SQL 关系型数据库 MySQL
临键锁引发的死锁
【8月更文挑战第4天】
40 0
临键锁引发的死锁
|
6月前
|
存储 安全 Java
12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
77 1
12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁
|
Linux API C++
锁、避免死锁等相关
锁、避免死锁等相关
67 0
《锁》有那些?
锁是计算机科学中用于控制对共享资源的访问的一种同步机制。不同种类的锁适用于不同的场景和需求。下面是一些常见的锁的种类及其详细介绍:
72 1
|
存储 算法 安全
辛辛苦苦的劳动成果,如何上把锁?
辛辛苦苦的劳动成果,如何上把锁?
|
数据可视化 Java
lock锁和死锁
lock锁和死锁
|
存储 对象存储
|
PHP
并发锁(二):共享锁和独占锁
并发锁(二):共享锁和独占锁
216 0
并发锁(二):共享锁和独占锁