java 可重入锁

Posted 偶像java练习生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 可重入锁相关的知识,希望对你有一定的参考价值。

1.公平锁,非公平锁

公平锁:非常公平,不能插队,必须先来后到!
非公平锁:非常不公平,可以插队,例子:一个线程3s 执行完,一个线程3h 执行完,先让3s 的执行,需要插队!

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

ReentranLock 默认是非公平锁
但是可以通过他的构造方法改变为公平锁: 如下

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

synchronized 锁也是非公平锁,所有的锁默认都是非公平锁,保证我们一个效率问题。

2. 可重入锁

所有的锁都是可重入锁,拿到外面的锁之后,就可以拿到里面的锁,自动获得

代码如下:

package com.lock;

//Synchronized
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();//这里面也有锁
     

    public synchronized void call()
        System.out.println(Thread.currentThread().getName()+"call");
    


输出结果:
Asms
Acall
Bsms
Bcall
A 拿到锁后先执行完毕,再B 执行

下面是LOCK 版的:

package com.lock;

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

public class Demo02 


    public static void main(String[] args) 
        Phone phone = new Phone();
        new Thread(()->
            phone.sms();
        ,"A").start();

        new Thread(()->
            phone.sms();
        ,"B").start();

    

class Phone2


        Lock lock = new ReentrantLock();

        public synchronized void sms()
            lock.lock();//细节问题:lock.lock 是拿的两把锁,lock.lock;,lock.unlock
            lock.lock()
            //lock 锁必须配对,否则就会死在里面
            try 
                System.out.println(Thread.currentThread().getName()+"sms");
                call();//这里面也有锁
             catch (Exception e) 
                e.printStackTrace();
             finally 
                lock.unlock();
                lock.unlock();
            
        

        public synchronized void call()
            lock.lock();
            try 
                System.out.println(Thread.currentThread().getName()+"call");
             catch (Exception e) 
                e.printStackTrace();
             finally 
                lock.unlock();
            
        

    



输出结果:
Asms
Acall
Bsms
Bcall

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;
    

我们来自定义下自旋锁:

package com.lock;

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

public class TestSpinLock 


 public static void main(String[] args) throws InterruptedException 
//        ReentrantLock reentrantLock = new ReentrantLock();
//        reentrantLock.lock();
//        reentrantLock.unlock();

     //底层使用的自旋锁
     SpinLockDemo lock = new SpinLockDemo();
     new Thread(()->
         try 
             lock.myLock();
             TimeUnit.SECONDS.sleep(3);
          catch (Exception e) 
             e.printStackTrace();
          finally 
             lock.myUnLock();
         
     ,"T1").start();

     TimeUnit.SECONDS.sleep(1);

     new Thread(()->
         try 
             lock.myLock();
             TimeUnit.SECONDS.sleep(1);
          catch (Exception e) 
             e.printStackTrace();
          finally 
             lock.myUnLock();
         
     ,"T2").start();


     lock.myLock();
     lock.myUnLock();



 



输出结果:
T1===> mylock
main===> mylock
T2===> mylock
T1==>myUnlock
T2==>myUnlock
main==>myUnlock

T1 解锁后T2 才能解锁,T1 在自旋,T1 解锁后,T2 解锁

4.死锁


死锁测试,怎么排除死锁:

package com.lock;

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 );
            
        

    

输出结果:
T2lock:lockB=>getlockA
T1lock:lockA=>getlockB
程序卡住了

解决程序卡住了的问题
1.使用jps 定位进程号
linux ls-l

而jps 则用jps -l 命令如下:


F:\\workSpace\\AWT>jps -l
2128 sun.tools.jps.Jps
2344 com.lock.DeadLockDemo
8024
15100 org.jetbrains.jps.cmdline.Launcher

可以查看到当前死锁的进程为 2344

  1. 使用 jstack 进程号 进程号找到死锁问题
    使用命令 jstack -2344 显示如下,翻到最底下:

    面试或者工作中! 排查问题:
    1.进程卡了看上线上有没有异常?
    异常:
  2. 使用日志查看
  3. 使用堆栈,信息
    如何解决死锁?
    解决死锁产生的条件就可以了!

以上是关于java 可重入锁的主要内容,如果未能解决你的问题,请参考以下文章

Java中锁分类

面试必备|Java中的公平锁和非公平锁,可重入锁,自旋锁

6.23Java多线程可重入锁实现原理

java 多线程-可重入锁

java中可重入锁和自旋锁

可重入锁