ToB企服应用市场:ToB评测及商务社交产业平台

标题: JUC并发编程(终章)各种锁的理解 [打印本页]

作者: 篮之新喜    时间: 2023-12-22 19:43
标题: JUC并发编程(终章)各种锁的理解
各种锁的理解

公平锁、非公平锁

公平锁:先到先得(不可插队)
非公平锁:达者为先(可插队)---------->默认
  1. public ReentrantLock() {
  2.     //默认非公平锁
  3.     sync = new NonfairSync();
  4. }
复制代码
  1. //重载的构造方法,通过fair控制是否公平
  2. public ReentrantLock(boolean fair) {
  3.     sync = fair ? new FairSync() : new NonfairSync();
  4. }
复制代码
可重入锁(递归锁)

所有的锁都是可重入锁

Synchronized版
  1. package org.example.lock;
  2. public class Demo01 {
  3.     public static void main(String[] args) {
  4.         phone1 p1 = new phone1();
  5.         new Thread(()->{
  6.             p1.ems();
  7.         },"A").start();
  8.         new Thread(()->{
  9.             p1.ems();
  10.         },"B").start();
  11.     }
  12. }
  13. class phone1{
  14.     public synchronized void ems(){
  15.         System.out.println(Thread.currentThread().getName()+"---------->ems");
  16.         call();
  17.     }
  18.     public synchronized void call(){
  19.         System.out.println(Thread.currentThread().getName()+"---------->call");
  20.     }
  21. }
复制代码
ems方法中包含了call方法,所以当我们调用ems方法获取到锁时,也把call方法的synchronized锁获取到了。
错误理论
正确理论
Lock版
  1. package org.example.lock;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;
  4. public class Demo02 {
  5.     public static void main(String[] args) {
  6.         phone2 p2 = new phone2();
  7.         new Thread(()->{
  8.             p2.ems();
  9.         },"A").start();
  10.         new Thread(()->{
  11.             p2.ems();
  12.         },"B").start();
  13.     }
  14. }
  15. class phone2{
  16.     Lock lock = new ReentrantLock();
  17.     public  void ems(){
  18.         lock.lock();
  19.         try {
  20.             System.out.println(Thread.currentThread().getName()+"---------->ems");
  21.             call();
  22.         } catch (Exception e) {
  23.             e.printStackTrace();
  24.         } finally {
  25.             //等待call方法锁解锁后再解锁
  26.             lock.unlock();
  27.         }
  28.     }
  29.     public void call(){
  30.         lock.lock();
  31.         try {
  32.             System.out.println(Thread.currentThread().getName()+"---------->call");
  33.         } catch (Exception e) {
  34.             e.printStackTrace();
  35.         } finally {
  36.             lock.unlock();
  37.         }
  38.     }
  39. }
复制代码
自旋锁

spinlock(不断尝试直至成功)
已经见过了,就是unsafe中的自增getAndAddInt方法中的do-while循环就是一把自旋锁

自己写一把锁
  1. package org.example.lock;
  2. import java.util.concurrent.TimeUnit;
  3. import java.util.concurrent.atomic.AtomicReference;
  4. public class SpinLockDemo {
  5.     //int 0
  6.     //Thread null
  7.     public static AtomicReference<Thread> atomic = new AtomicReference<>();
  8.     public static void lock(){
  9.         Thread thread = Thread.currentThread();
  10.         System.out.println("===============>"+thread.getName()+"===========>lock");
  11.         //自旋锁,若线程等于null,则compareAndSet为true,加!就为false,就会一直循环
  12.         while (!atomic.compareAndSet(null,thread)){
  13.         }
  14.     }
  15.     public static void unlock(){
  16.         Thread thread = Thread.currentThread();
  17.         System.out.println("===============>"+thread.getName()+"===========>unlock");
  18.         //自旋锁
  19.         atomic.compareAndSet(thread,null);
  20.     }
  21.     public static void main(String[] args) throws InterruptedException {
  22.         new Thread(()->{
  23.             try {
  24.                 lock();
  25.                 TimeUnit.SECONDS.sleep(10);
  26.             } catch (Exception e) {
  27.                 e.printStackTrace();
  28.             } finally {
  29.                 unlock();
  30.             }
  31.         },"A").start();
  32.         TimeUnit.SECONDS.sleep(1);
  33.         new Thread(()->{
  34.             try {
  35.                 lock();
  36.                 TimeUnit.SECONDS.sleep(2);
  37.             } catch (Exception e) {
  38.                 e.printStackTrace();
  39.             } finally {
  40.                 unlock();
  41.             }
  42.         },"B").start();
  43.     }
  44. }
复制代码
死锁

死锁是什么

死锁测试
  1. package org.example.lock;
  2. import java.util.concurrent.TimeUnit;
  3. public class DeadLockDemo {
  4.     public static void main(String[] args) {
  5.         String a = "A";
  6.         String b = "B";
  7.         new Thread(()->{new MyThread(a, b).run();},"A").start();
  8.         new Thread(()->{new MyThread(b, a).run();},"B").start();
  9.     }
  10. }
  11. class MyThread implements Runnable{
  12.     private String lockA;
  13.     private String lockB;
  14.     public MyThread(String lockA, String lockB) {
  15.         this.lockA = lockA;
  16.         this.lockB = lockB;
  17.     }
  18.     @Override
  19.     public void run() {
  20.         synchronized (lockA){
  21.             System.out.println(Thread.currentThread().getName()+"lock:"+lockA+"=>get"+lockB);
  22.             try {
  23.                 TimeUnit.SECONDS.sleep(2);
  24.             } catch (InterruptedException e) {
  25.                 throw new RuntimeException(e);
  26.             }
  27.             synchronized (lockB){
  28.                 System.out.println(Thread.currentThread().getName()+"lock:"+lockB+"=>get"+lockA);
  29.             }
  30.         }
  31.     }
  32. }
复制代码
程序突然卡住死锁如何排查?
1、使用jps-l定位进程号

查看当前java活着的进程
2、使用jstack 进程号查看死锁问题


查找到一个死锁问题!
面试或者工作中排查问题:
1、查看异常
2、查看日志
3、查看堆栈信息

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4