首页 > 其他分享 >2022.8.21 各种锁理解

2022.8.21 各种锁理解

时间:2022-08-21 23:44:28浏览次数:60  
标签:lockA 21 Thread lock 理解 线程 2022.8 new public

21、各种锁理解

1、公平锁和非公平锁:

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

非公平锁:非常不公平,可以插队(默认都是非公平)

2、可重入锁

递归锁

 

 

可重入锁synchronized 版本

 package com.xing.lock;
 ​
 //Synchorized
 public class Demo01 {
     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(); //这里也有锁(sms锁 里面的call锁)
    }
     public synchronized void call(){
         System.out.println(Thread.currentThread().getName() + "call");
    }
 }
 ​

 

 

可重入锁Lock版本(递归锁 )

 package com.xing.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.sms();
        },"a").start();
         new Thread(()->{
             phone.sms();
        },"b").start();
 ​
    }
 }
 class Phone2{
     Lock lock = new ReentrantLock();
     public void sms(){
         lock.lock();//细节问题 第一把锁
         //lock锁必须配对否则就会死在里面
         try {
             System.out.println(Thread.currentThread().getName() + "sms");
             call(); //这里也有锁(sms锁 里面的call锁)
        } catch (Exception e) {
             e.printStackTrace();
        }finally {
             lock.unlock();
        }
 ​
    }
     public synchronized void call(){
         lock.lock();//第二把锁
         try {
             System.out.println(Thread.currentThread().getName() + "call");
        } catch (Exception e) {
             e.printStackTrace();
        }finally {
             lock.unlock();
        }
 ​
 ​
    }
 }
 ​

 

 

总结:两个锁只要获得外面的锁之后,就能够拿到里面的锁,Lock和synchronized 的区别在需要手动释放锁,并且枷锁的次数和释放的次数要一样

3、自旋锁( spinlock )

不断尝试直到成功为止

 

 

自己创建一个自己的锁用CAS完成

 package com.xing.lock;
 ​
 import java.util.concurrent.atomic.AtomicReference;
 ​
 //自己写的自旋锁
 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);
    }
 }
 ​
 ​

然后去用线程调用

 package com.xing.lock;
 ​
 import java.util.concurrent.TimeUnit;
 ​
 public class TestSpinlock {
     public static void main(String[] args) {
         /*ReentrantLock reentrantLock = new ReentrantLock();
         reentrantLock.lock();
         reentrantLock.unlock();*/
         
         //底层的是自旋锁CAS实现的
         SpinlockDemo spinlockDemo = new SpinlockDemo();
 ​
         new Thread(()->{
             spinlockDemo.myLock();
             try {
                 TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                 e.printStackTrace();
            }finally {
                 spinlockDemo.myUnLock();
            }
        },"T1").start();
 ​
         //T1获得锁,T2一直在自旋。T1解锁后,T2才获得锁结束自旋
         new Thread(()->{
             spinlockDemo.myLock();
             try {
                 TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                 e.printStackTrace();
            }finally {
                 spinlockDemo.myUnLock();
            }
        },"T2").start();
 ​
 ​
    }
 }
 ​

总结:B线程这里一定会等待T1完成比较交换这个时候自旋锁里已经被A占着了(自旋锁条件:线程不为空及自转)所以B线程会一直自旋到A线程完成CAS的比较交换完成才不在进行自旋操作再进入到myunlock里完成解锁操作

优点:

自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快。

缺点:

如果某个线程持有锁的时间过长,就会导致其它等待获取锁的线程进入循环等待,消耗CPU。使用不当会造成CPU使用率极高。

上面Java实现的自旋锁不是公平的,即无法满足等待时间最长的线程优先获取锁。不公平的锁就会存在“线程饥饿”问题。

4、死锁

死锁测试,怎么排除死锁

 package com.xing.lock;
 ​
 import single.LazyMan;
 ​
 import java.util.concurrent.TimeUnit;
 ​
 public class DeadlockDemo {
     public static void main(String[] args) {
         String lockA = "lockA";
         String lockB = "lockB";
         // A想拿B
         new Thread(new MyThread(lockA,lockB),"T1").start();
         // B想拿A
         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){
             //lockA想拿B
             System.out.println(Thread.currentThread().getName() + "lock"+ lockA + "=> get" + lockB);
             try {
                 TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                 e.printStackTrace();
            }
             synchronized (lockB){
                 //B想拿A
                 System.out.println(Thread.currentThread().getName() + "lock" + lockB + "=> get" + lockA);
            }
        }
    }
 }
 ​

 

 

死锁排查

1、使用jps -l定位进程号

例如:在终端输入jps -l

 

 

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

例如:jstack 11444

 

 

 

标签:lockA,21,Thread,lock,理解,线程,2022.8,new,public
From: https://www.cnblogs.com/shanzha/p/16611427.html

相关文章

  • 8.21
    ABC249G题意:给定\(n\)张牌,每张牌正面是\(a_i\),背面是\(b_i\),要求从里面任选最少一张牌,使得证明的数字异或和不超过\(m\)的同时,背面数字异或和最大。\(n\leq2000,m,a_i,......
  • 2022.8.21 多校周报
    总结牛客第九场A一眼看出是尺取法,就A了。B一道很简单的概率dp,状态和转移方程都写出来了,但想着搞前缀和优化,没想到差分,就卡死了,有点可惜。G马拉车加哈希,但卡了除了双......
  • 打碎自己,理解自己,重塑自己
    我不得不去打碎自己,对着掉落的碎片一点一点地去发现身上的问题,然后一块块地去解决,或者去接受,要么改正自己的缺点,要么接受自己的缺点。关于爱情。ztt为什么拉黑你。......
  • 2022.8.21 线程池
    11、线程池(重点)线程池Executors:3大方法、7大参数、4种拒绝策略池化技术程序的运行,本质:占用系统的资源!优化资源的使用!==>引进了一种技术池化池线程池、连接池、内......
  • 2022.8.21 四大函数式接口与Stream流式计算
    12、四大函数式接口(重点)   函数接口:只有一个方法的接口    @FunctionalInterface publicinterfaceRunnable{     publicabstractvoidrun(......
  • 2022.8.21 Forkjoin与异步回调
    14、Forkjoin(分支合并)什么是ForkJoinForkJoin在JDK1.7, 并行执行任务!提高效率。在大数据量中!大数据:MapReduce(把大任务拆分为小任务)Forkjoin特点:工作窃取,这里......
  • 2022.8.21 读写锁与阻塞队列
    9、读写锁   自定义的缓存,没有加锁,就会出现一个没有写入完成,另一个突然插进来的情况 packagecom.xing.rw; ​ importjava.util.HashMap; importjava.util.......
  • 2022.8.21 JUC
    1、什么是JUC1、什么是juc(学习方法:官方文档+源码)   JUC——(java.util.concurrent)是一个包名的缩写,java工具类下的一个并发功能的包。该包下存放的均为多线程相......
  • 2022-08-21 假突破立即做空,就如同突破收敛三角就做单一样,总会给你一段利润。
     同样是假突破,第二次上冲。左边完成了整个4h标准中枢,右边又形成了30分钟的笔中枢扩展。左边4h图,假突破之后,完成了4h一个全部线段中枢的上涨。最后一段是背驰段,结束了30......
  • 2022.8.21
    1.学习了MCS最大势算法,补充了弦图几个性质和konig定理的证明,做完了PPT。2.继续做了2道网络流24题,几道弦图相关的题目,看了昨天的CF,D题不是很懂3.最大流最小割定理,弦图是......