可重入锁与读写锁

2019-12-26  本文已影响0人  Aeroball
可重入锁:

  可重入锁,也叫递归锁,指定是同一线程 外层函数获得锁之后,内层递归函数仍可以再次获取锁而不会出现死锁。

public class WhatReentrant{
    public static void main(String[] args){
        new Thread(() -> {
            synchronized (this) {
                System.out.println("第一次获取锁,这个锁是:" + this);
                int index = 1;
                while (true) {
                    synchronized (this) {
                        System.out.println("第" + (++index) + "次获取锁,这个锁是:" + this);
                    }
                    if (index == 10) {
                        break;
                    }
                }
            }
        }).start();
    }
}
public class WhatReentrant2 {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        
        new Thread(() -> {
            try {
                lock.lock();
                System.out.println("第1次获取锁,这个锁是:" + lock);
                int index = 1;
                while (true) {
                    try {
                        lock.lock();
                        System.out.println("第" + (++index) +"次获取锁,这个锁是:" + lock);
                        try {
                            Thread.sleep(new Random().nextInt(200));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        if (index == 10) {
                            break;
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            } finally {
                lock.unlock();
            }       
        }).start();
    }
}
public class Restaurant {
    private Lock windows = new ReentrantLock();

    public void getMeals() throws Exception {
        try {
            windows.lock();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "打饭");
        } finally {
            windows.unlock();
        }
    }

    public void getSoup() throws Exception {
        try {
            windows.lock();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "打汤");
        } finally {
            windows.unlock();
        }
    }

    public void today() throws Exception {
        try {
            windows.lock();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "打饭");
            getMeals();
            getSoup();
        } finally {
            windows.unlock();
        }
    }

    public static void main(String[] args) {
        Restaurant test = new Restaurant();
        new Thread(() -> {
            try {
                test.today();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "我").start();

        new Thread(() -> {
            try {
                test.getSoup();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "某人").start();

        new Thread(() -> {
            try {
                test.getMeals();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "另一个人").start();
    }
}
输出:
我打饭
我打饭
我打汤
某人打汤
另一个人打饭

可以发现以上都没有发生死锁,可以多次获取相同的锁
可重入锁有:

注意:
  ReentrantLock和synchronized不一样,需要手动释放锁,所以使用ReentrantLock的时候一定要手动释放锁,并且加锁的次数和释放次数要一样

读写锁
  1. 为什么需要读写锁?
      在多线程的环境下,对同一份数据进行读写,会涉及到线程安全问题。比如在一个线程读取数据的时候,另一个线程正在写数据,而导致前后数据的不一致性;一个线程在写数据的时候,另一个线程也在写数据,同样会导致数据的不一致性。
      这时可以在读写方法中加入互斥锁,任何时候只能允许一个线程的一个读写操作,这样是可以解决问题,但是效率却大打折扣了。因为在真实的业务场景中,读取数据的操作次数通常高于写入数据的操作,而线程之间的读读操作不涉及线程安全问题,没有必要加入互斥锁,只要在读-写,写写期间上上锁即可。
读写锁机制:
    - 读-读不互斥
    - 读-写互斥
    - 写-写互斥
public class ReadWriteLockTest {

    private static ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    private static ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();  //拿到读锁
    private static ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock(); //写锁


    public static void read() {
        readLock.lock();
        try{
            System.out.println("read method ================");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }finally {
            readLock.unlock();
        }

    }

//    public static void read1() {
    public static void write() {
        writeLock.lock();
        try{
            System.out.println("read method >>>>>>>>>>>>>>>>>>>>>");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }finally {
            writeLock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            ReadWriteLockTest.write();
        }).start();

        new Thread(() -> {
            ReadWriteLockTest.read();
        }).start();

        Thread.sleep(10000);
    }
}

上一篇 下一篇

猜你喜欢

热点阅读