Java深入学习11:Lock锁详解

Posted wobuchifanqie

tags:

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

Java深入学习11:Lock锁详解

 一、Lock锁是什么

   java.util.concurrent.locks包下常用的类与接口(lock是jdk 1.5后新增的)

  Lock 接口支持那些语义不同(重入、公平等)的锁规则,可以在非阻塞式结构的上下文(包括 hand-over-hand 和锁重排算法)中使用这些规则。主要的实现是 ReentrantLock。

  Lock 实现提供了比 synchronized 关键字 更广泛的锁操作,它能以更优雅的方式处理线程同步问题。也就是说,Lock提供了比synchronized更多的功能。

二、代码分析

1-Lock类方法说明

public interface Lock {
    
    //获取锁方式1:最常用的方式。如果当前锁不可用,当前线程无法调度并进入休眠状态直到获取到锁
    void lock();
    
    //获取锁方式2:获取锁(除非当前线程被中断)。如果当前锁不可用,当前线程无法调度并进入休眠状态直到当前线程获取到锁或者其它线程中断了当前的线程
    void lockInterruptibly() throws InterruptedException;
   
     //获取锁方式3:获取锁(仅当锁在调用时处于空闲状态时才获取锁)。如果成功获取锁,返回true,否则,返回false;
    boolean tryLock();
     
     //获取锁方式4:获取锁(在规定的等待时间内且线程没有被中断,如果锁处于空闲状态时则获取锁)。如果成功获取锁,返回true,否则,返回false;
    //如果当前锁不可用,当前线程无法调度并进入休眠状态直到(1)当前线程获取到锁(2)当前线程被其它线程中中断(3)等待时间结束
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    
    //释放锁
    void unlock();

    //返回绑定到此 Lock 实例的新 Condition 实例
    Condition newCondition();
}

 

2-Lock锁四种方法的使用方法(ReentrantLock是 Lock 的实现类)

  2-1- lock()

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

public class LockTest {

    public static void main(String[] args) {

        LockDemo lockDemo = new LockDemo();
        new Thread(lockDemo,"thread 1").start();
        new Thread(lockDemo,"thread 2").start();
        new Thread(lockDemo,"thread 3").start();
    }
}
class LockDemo implements  Runnable{

    Lock lock = new ReentrantLock();

    @Override
    public void run() {
        //上锁
        lock.lock();
        try {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+" get the lock");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放锁
            System.out.println(Thread.currentThread().getName()+" realse the lock");
            lock.unlock();
        }
    }
}
-----------------------------日志输出----------------------------
thread 1 get the lock
thread 1 realse the lock
thread 2 get the lock
thread 2 realse the lock
thread 3 get the lock
thread 3 realse the lock

 

  2-2-tryLock()

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

public class TryLockTest {

    public static void main(String[] args) {

        TryLockDemo lockDemo = new TryLockDemo();
        new Thread(lockDemo,"thread 1").start();
        new Thread(lockDemo,"thread 2").start();
        new Thread(lockDemo,"thread 3").start();
    }
}
class TryLockDemo implements  Runnable{

    Lock lock = new ReentrantLock();

    @Override
    public void run() {
        //上锁
        if (lock.tryLock()) {
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName()+" get lock success");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //释放锁
                System.out.println(Thread.currentThread().getName()+" realse the lock");
                lock.unlock();
            }
        }else{
            System.out.println(Thread.currentThread().getName() +" get lock fail");
        }

    }
}
-------------------------------日志--------------------------------------
thread 2 get lock fail
thread 3 get lock fail
thread 1 get lock success
thread 1 realse the lock

 

  2-3- tryLock(long time, TimeUnit unit) 

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

public class TryLockParamTest {

    public static void main(String[] args) {

        TryLockParamDemo lockDemo = new TryLockParamDemo();
        new Thread(lockDemo,"thread 1").start();
        new Thread(lockDemo,"thread 2").start();
        new Thread(lockDemo,"thread 3").start();
    }
}

class TryLockParamDemo implements  Runnable{

    Lock lock = new ReentrantLock();

    @Override
    public void run() {
        try {
            //上锁
            if (lock.tryLock(3L,TimeUnit.SECONDS)) {
                try {
                    Thread.sleep(2000);
                    System.out.println(Thread.currentThread().getName()+" get lock success");
                } finally {
                    //释放锁
                    System.out.println(Thread.currentThread().getName()+" realse the lock");
                    lock.unlock();
                }
            }else{
                System.out.println(Thread.currentThread().getName() +" get lock fail");
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

--------------------------------日志--------------------------------------
thread 1 get lock success
thread 1 realse the lock
thread 3 get lock fail
thread 2 get lock success
thread 2 realse the lock

 

  2-4- lockInterruptibly()

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

public class LockInterruptiblyTest {

    public static void main(String[] args) {

        //1-开启第一个线程,期间会sleep 1秒
        LockInterruptiblyDemo lockDemo = new LockInterruptiblyDemo();
        new Thread(lockDemo,"thread 1").start();
        //2-开启第二个线程,需要等待第一个线程释放锁,才能进入
        Thread thread2 = new Thread(lockDemo, "thread 2");
        thread2.start();
        //3-开启第三个线程,用于中断第二个线程
        LockInterruptDemo lockInterruptDemo = new LockInterruptDemo(thread2);
        new Thread(lockInterruptDemo,"thread 3").start();
        //预计结果,第一个线程成功获取锁并释放锁,但第二个线程会被中断无法成功获取锁
    }
}
//测试线程target
class LockInterruptiblyDemo implements  Runnable{

    Lock lock = new ReentrantLock();

    @Override
    public void run() {
        try {
            lock.lockInterruptibly();
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName()+ " get lock success");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName()+ " release lock success");
                lock.unlock();
            }
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName() + " has been interrupted and get lock unsuccessfully");
        }


    }
}

//用于中断其它线程的线程taget
class LockInterruptDemo implements Runnable{

    private Thread thread;

    public LockInterruptDemo(Thread thread) {
        this.thread = thread;
    }

    @Override
    public void run() {
        //中断目标线程
        thread.interrupt();
        System.out.println(Thread.currentThread().getName() +" run success ");
        System.out.println(Thread.currentThread().getName() +" has interrupted  " + thread.getName() +"successfully");
    }
}

------------------------------------日志-----------------------------------
thread 3 run success 
thread 2 has been interrupted and get lock unsuccessfully
thread 3 has interrupted  thread 2successfully
thread 1 get lock success
thread 1 release lock success

 

3- Lock和synchronized对比

 1)synchronized是Java语言的关键字,因此是内置特性,Lock不是Java语言内置的,Lock是一个接口,通过实现类可以实现同步访问。

 2)synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中

 3)在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态。

 

以上是关于Java深入学习11:Lock锁详解的主要内容,如果未能解决你的问题,请参考以下文章

“全栈2019”Java多线程第二十七章:Lock获取lock/释放unlock锁

Java多线程学习之Lock与ReentranLock详解

深入研究 Java Synchronize 和 Lock 的区别与用法

java 锁 Lock接口详解

第78题JAVA高级技术-多线程12(同步锁-lock)

深入浅出 Java Concurrency (11): 锁机制 part 6 CyclicBarrier