多线程高并发编程(2) -- 可重入锁介绍和自定义

背景:

  什么是 “可重入”?可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。即可重入锁的作用就是为了避免死锁,java中synchronized和ReentrantLock都是可重入锁。

  //synchronized 可重入锁
    private void test() {
        //  第一次获得锁
        synchronized (this) {
            while (true) {
                //  第二次获得同样的锁
                synchronized (this) {
                    System.out.println("ReentrantLock!");
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

  //ReentrantLock可重入锁
    Lock lock = new ReentrantLock();
    private void test1() {
        lock.lock();
        try {
            test2();
        } finally {
            lock.unlock();
        }
    }
    private void test2() {
        lock.lock();
        try {
            System.out.println("ReentrantLock!");
        } finally {
            lock.unlock();
        }
    }

一.自定义不可重入锁

  所谓不可重入锁,即若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞。下面的线程执行test1()方法首先获取lock,接下来执行test2()方法就无法执行test2()中的逻辑,必须先释放锁。

// 不可重入锁
class Lock {
    //是否占用
    private boolean isLocked = false;

    //使用锁
    public synchronized void lock() {
        while (isLocked) {//已经占用
            try {
                this.wait();//等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isLocked = true;//修改标识为已经占用
    }

    //释放锁
    public synchronized void unLock() {
        isLocked = false;//修改标识为未占用
        notify();//唤醒等待线程
    }

}
============使用===========
    Lock lock = new Lock();

    public void test1() {
        lock.lock();
        test2();
        lock.unLock();
    }

    private void test2() {
        lock.lock();
        //...
        lock.unLock();
    }

二.自定义可重入锁

   流程:

  1. 定义锁占用标识、存储线程、线程锁持有数量;
  2. 使用锁:判断是否已经占用和当前线程是否不等于存储线程,如果条件符合进入等待,不符合则修改占用标识、存储线程为当前线程、线程锁数量+1;
  3. 释放锁:判断当前线程是否等于存储线程,条件符合则线程锁数量-1,当线程锁数量=0时,修改占用标识,唤醒等待线程,将存储线程置为null;
// 可重入锁
class ReLock{
    //是否占用
    private boolean isLocked = false;
    private Thread lockedBy = null; //存储线程
    private int holdCount = 0;
    //使用锁
    public synchronized void lock() throws InterruptedException {
        Thread t = Thread.currentThread();
        while(isLocked && lockedBy != t) {
            wait();
        }
        isLocked = true;
        lockedBy = t;
        holdCount ++;
    }
    //释放锁
    public synchronized void unlock() {
        if(Thread.currentThread() == lockedBy) {
            holdCount --;
            if(holdCount ==0) {
                isLocked = false;
                notify();
                lockedBy = null;
            }        
        }        
    }
    public int getHoldCount() {
        return holdCount;
    }
}
==============使用===============
public class LockTest {
    ReLock lock = new ReLock();
    public void test1() throws InterruptedException {
        lock.lock();
        System.out.println(lock.getHoldCount());
        test2();
        lock.unlock();
        System.out.println(lock.getHoldCount());
    }
    //可重入
    public void test2() throws InterruptedException {
        lock.lock();
        System.out.println(lock.getHoldCount());
        //...................
        lock.unlock();
        System.out.println(lock.getHoldCount());
    }
    public static void main(String[] args) throws InterruptedException {
        LockTest lockTest= new LockTest();
        lockTest.test1();            
        Thread.sleep(1000);        
        System.out.println(lockTest.lock.getHoldCount());
    }

}
posted @ 2020-04-16 14:02  码猿手  阅读(...)  评论(...编辑  收藏
Live2D