多线程进阶-JUC

56 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天

各种锁的理解

1、公平锁、非公平锁

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

 /**
  * Creates an instance of {@code ReentrantLock}.
  * This is equivalent to using {@code ReentrantLock(false)}.
  */
 public ReentrantLock() {
     sync = new NonfairSync();
 }
 ​

非公平锁:非常不公平,允许插队的,可以改变顺序。

 /**
  * Creates an instance of {@code ReentrantLock} with the
  * given fairness policy.
  *
  * @param fair {@code true} if this lock should use a fair ordering policy
  */
 public ReentrantLock(boolean fair) {
     sync = fair ? new FairSync() : new NonfairSync();
 }
 ​

2、可重入锁

可重入锁(递归锁)

image-20221012202510381

Synchronized锁

 public class Demo1 {
     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" );
     }
 }
 ​

lock锁

 //lock
 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();//这里也有一把锁
         } catch (Exception e) {
             e.printStackTrace();
         }finally {
             lock.unlock();
         }
     }
     public void call(){
         lock.lock();
         try {
             System.out.println(Thread.currentThread().getName() + "=> call");
         }catch (Exception e){
             e.printStackTrace();
         }
         finally {
             lock.unlock();
         }
     }
 }
 ​
  • lock锁必须配对,相当于lock和 unlock 必须数量相同;
  • 在外面加的锁,也可以在里面解锁;在里面加的锁,在外面也可以解锁;

3、自旋锁

spinlock

 public final int getAndAddInt(Object var1, long var2, int var4) {
     int var5;
     do {
         var5 = this.getIntVolatile(var1, var2);
     } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
     return var5;
 }
 ​

自我设计自旋锁:

 public class SpinlockDemo {
 ​
     //int 0
     //thread null
     AtomicReference<Thread> atomicReference=new AtomicReference<>();
 ​
     //加锁
     public void myLock(){
         Thread thread = Thread.currentThread();
         System.out.println(thread.getName()+"===> mylock");
 ​
         //自旋锁
         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 {
         ReentrantLock reentrantLock = new ReentrantLock();
         reentrantLock.lock();
         reentrantLock.unlock();
 ​
 ​
         //使用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();
     }
 }
 ​

运行结果:

t2进程必须等待t1进程Unlock后,才能Unlock,在这之前进行自旋等待。。。。

image-20221012233338145

4、死锁

死锁是什么?

image-20221012233359000

死锁测试,怎么排除死锁

 package com.ogj.lock;
 ​
 import java.util.concurrent.TimeUnit;
 ​
 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、使用jps定位进程号,jdk的bin目录下: 有一个jps

命令:jps -l

image-20221012233426831

2、使用jstack 进程进程号 找到死锁信息

image-20221012233451614

一般情况信息在最后:

image-20221012233516221

面试,工作中!排查问题!

1、日志

2、堆栈信息