并发编程-concurrent指南-Lock-可重入锁(ReentrantLock)

Posted qjm201000

tags:

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

可重入和不可重入的概念是这样的:当一个线程获得了当前实例的锁,并进入方法A,这个线程在没有释放这把锁的时候,能否再次进入方法A呢?

  • 可重入锁:可以再次进入方法A,就是说在释放锁前此线程可以再次进入方法A(方法A递归)。
  • 不可重入锁(自旋锁):不可以再次进入方法A,也就是说获得锁进入方法A是此线程在释放锁钱唯一的一次进入方法A。

,具体区别查看可重入锁和不可重入锁区别

 

ReentrantLock,意思是“可重入锁”。ReentrantLock是唯一实现了Lock接口的类,并且ReentrantLock提供了更多的方法。下面通过一些实例看具体看一下如何使用ReentrantLock。

lock()的正确使用方法

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

public class MainLock {
    private Lock lock = new ReentrantLock();
    public static void main(String[] args) {
        final MainLock mainLock = new MainLock();

        new Thread(new Runnable() {
            @Override
            public void run() {
                mainLock.insert(Thread.currentThread());
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                mainLock.insert(Thread.currentThread());
            }
        }).start();
    }

    public void insert(Thread thread){
        lock.lock();//获取锁
        try{
            System.out.println(thread.getName() + "获取锁");
            for(int i=0;i<5;i++){
                System.out.println("------------------------" + thread.getName() + ":"+i+"------------------------");
            }
        }finally {
            System.out.println(thread.getName() + "释放锁");
            lock.unlock();//释放锁
        }
    }
}

结果:

Thread-0获取锁
------------------------Thread-0:0------------------------
------------------------Thread-0:1------------------------
------------------------Thread-0:2------------------------
------------------------Thread-0:3------------------------
------------------------Thread-0:4------------------------
Thread-0释放锁
Thread-1获取锁
------------------------Thread-1:0------------------------
------------------------Thread-1:1------------------------
------------------------Thread-1:2------------------------
------------------------Thread-1:3------------------------
------------------------Thread-1:4------------------------
Thread-1释放锁

 

tryLock()的使用方法

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

public class MainTryLock {
    private Lock lock = new ReentrantLock();
    public static void main(String[] args) {
        final MainTryLock mainTryLock = new MainTryLock();

        new Thread(){
            @Override
            public void run() {
                mainTryLock.insert(Thread.currentThread());
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                mainTryLock.insert(Thread.currentThread());
            }
        }.start();
    }

    public void insert(Thread thread){
        if(lock.tryLock()){
            try{
                System.out.println(thread.getName() + "获取锁");
                for(int i=0;i<5;i++){
                    Thread.sleep(200);
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                System.out.println(thread.getName() + "释放锁");
                lock.unlock();//释放锁
            }
        }else{
            System.out.println(thread.getName()+"未获取到锁");
        }
    }
}

结果:

Thread-0获取锁
Thread-1未获取到锁
Thread-0释放锁

 

lockInterruptibly()响应中断的使用方法:

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

public class MainLockInterruptibl {
    private  Lock lock = new ReentrantLock();
    public static void main(String[] args)  {
        MainLockInterruptibl test = new MainLockInterruptibl();
        MyThread thread1 = new MyThread(test);
        MyThread thread2 = new MyThread(test);
        thread1.start();
        thread2.start();

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread2.interrupt();
    }

    public void insert(Thread thread) throws InterruptedException{
        lock.lockInterruptibly();   //注意,如果需要正确中断等待锁的线程,必须将获取锁放在外面,然后将InterruptedException抛出
        try {
            System.out.println(thread.getName()+"得到了锁");
            long startTime = System.currentTimeMillis();
            for( int i=0;i<5;i++) {
                TimeUnit.SECONDS.sleep(2);
            }
        } catch (Exception e){
            e.printStackTrace();
        }finally {
            System.out.println(Thread.currentThread().getName()+"执行finally");
            lock.unlock();
            System.out.println(thread.getName()+"释放了锁");
        }
    }
    static class MyThread extends Thread {
        private MainLockInterruptibl test = null;
        public MyThread(MainLockInterruptibl test) {
            this.test = test;
        }
        @Override
        public void run() {
            try {
                test.insert(Thread.currentThread());
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println(Thread.currentThread().getName()+"被中断");
            }
        }
    }
}

结果:

Thread-0得到了锁
java.lang.InterruptedException
Thread-1被中断
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
    at com.concurrent.MainLockInterruptibl.insert(MainLockInterruptibl.java:25)
    at com.concurrent.MainLockInterruptibl$MyThread.run(MainLockInterruptibl.java:48)
Thread-0执行finally
Thread-0释放了锁

 

源码地址:https://github.com/qjm201000/concurrent_reentrantLock.git

以上是关于并发编程-concurrent指南-Lock-可重入锁(ReentrantLock)的主要内容,如果未能解决你的问题,请参考以下文章

redis并发读写锁,使用Redisson实现分布式锁

并发编程—4显式锁 Lock

并发编程7:深入理解Java虚拟机-锁优化

初识Lock与AbstractQueuedSynchronizer(AQS)

8.初识Lock与AbstractQueuedSynchronizer(AQS)

并发编程-concurrent指南-ConcurrentMap