一步步学习多线程(七) ReentrantLock

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/money9sun/article/details/82661335

ReentrantLock是一个锁,相对于synchronized, 这个锁更灵活,可以灵活的加锁和解锁。

我们先看一个例子

public class ReenterLock implements Runnable {
    public static ReentrantLock lock = new ReentrantLock();
    public static int count = 0;
    
    @Override
    public void run() { 
        for (int i = 0; i < 10000; i++) {
            lock.lock();
            try{
                count++;                
            }finally{
                lock.unlock();   // 防止发生某些意外,锁没有释放掉,其他线程无法进入
            }
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        ReenterLock rl = new ReenterLock();
        Thread t1 = new Thread(rl);
        Thread t2 = new Thread(rl);
        t1.start();t2.start();
        t1.join();t2.join();
        System.out.println(count);
    }
}

如果对一段代码加了两个锁,例如

lock.lock();

lock.lock();

在解锁的时候,要执行两次unlock(),

lock.unlock();

lock.unlock();

二、可中断

ReentrantLock还有一个特性,就是可中断,在加锁的同时可以响应中断,让我们看下面这个例子:

public class ReenterLockInterrupt extends Thread {

    public static ReentrantLock reenlock1 = new ReentrantLock();
    public static ReentrantLock reenlock2 = new ReentrantLock();

    public int lock;

    public ReenterLockInterrupt(int lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        try {

            if (lock == 1) {
                reenlock1.lockInterruptibly();  // 可以被中断的lock
                Thread.sleep(1000);
                reenlock2.lockInterruptibly();  // 可以被中断的lock
            } else {
                reenlock2.lockInterruptibly();  // 可以被中断的lock
                Thread.sleep(1000);
                reenlock1.lockInterruptibly();  // 可以被中断的lock
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if(reenlock1.isHeldByCurrentThread()){
                reenlock1.unlock();
            }
            if(reenlock2.isHeldByCurrentThread()){
                reenlock2.unlock();
            }
            System.out.println(Thread.currentThread().getId() + ":线程退出");
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        ReenterLockInterrupt t1 = new ReenterLockInterrupt(1);
        ReenterLockInterrupt t2 = new ReenterLockInterrupt(2);
        t1.start();
        t2.start();
        Thread.sleep(1000);
        //t1.interrupt();
    }

}

当我们把//t1.interrupt(); 注释掉的时候,程序就会一直处在运行状态

控制台输入 $ jstack 54728

2018-09-12 15:31:00
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.172-b11 mixed mode):

"Attach Listener" #12 daemon prio=9 os_prio=31 tid=0x00007fcb12819000 nid=0x1407 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"DestroyJavaVM" #11 prio=5 os_prio=31 tid=0x00007fcb12818000 nid=0x1c03 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Thread-1" #10 prio=5 os_prio=31 tid=0x00007fcb13067800 nid=0x4f03 waiting on condition [0x000070000175f000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007955f5808> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
    at cn.eric.thread.lock.reentrant.ReenterLockInterrupt.run(ReenterLockInterrupt.java:27)

"Thread-0" #9 prio=5 os_prio=31 tid=0x00007fcb12023800 nid=0x4d03 waiting on condition [0x000070000165c000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007955f5838> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
    at cn.eric.thread.lock.reentrant.ReenterLockInterrupt.run(ReenterLockInterrupt.java:23)

可以看到死锁发生在(ReenterLockInterrupt.java:23)这里。如果我们把最后一行的注释注释掉,程序就可以关闭了。当然这样进行线程的打扰还是比较简单的,大家有兴趣可以自己写检测线程死锁的方法

三、可限时

可限时也是一种避免死锁和长期等待的措施,主要方法 tryLock(5,TimeUnit.SECONDS)

public class ReenterLockTime implements Runnable {
    public static ReentrantLock lock = new ReentrantLock();
    public static int count = 0;
    
    @Override
    public void run() {
            
        try {
            if(lock.tryLock(5, TimeUnit.SECONDS)){
                System.out.println(Thread.currentThread().getId() + "get lock success");
                Thread.sleep(6000);
            }else{
                System.out.println(Thread.currentThread().getId() + "get lock failed");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            if(lock.isHeldByCurrentThread())
                lock.unlock();
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        ReenterLockTime rl = new ReenterLockTime();
        Thread t1 = new Thread(rl);
        Thread t2 = new Thread(rl);
        t1.start();t2.start();
    }
}

输出:

9get lock success
10get lock failed

四、公平锁

公平锁保证线程先来先得锁,后来后得锁

例子:

public class ReenterLockFair implements Runnable{
    //创建公平锁
    private static ReentrantLock lock=new ReentrantLock(true);
    public void run() {
        while(true){
            lock.lock();
            try{
                System.out.println(Thread.currentThread().getName()+"线程得锁");
            }finally{
                lock.unlock();
            }
        }
    }
    public static void main(String[] args) {
        ReenterLockFair rlf=new ReenterLockFair();
        Thread t1=new Thread(rlf);
        Thread t2=new Thread(rlf);
        t1.start();
        t2.start();
    }
}

猜你喜欢

转载自blog.csdn.net/money9sun/article/details/82661335
今日推荐