ReentrantLock代替synchronized

1、ReentrantLock是手工锁,锁住的是ReentrantLock对象,synchronized是自动锁,会自动释放锁,锁住的是堆内存中的对象。synchronized,在代码遇到异常的时候,JVM会自动释放锁。ReentrantLock则不会。

/**
 * ReentrantLock替代synchronized
 */
public class ReentrantLock2 {

    ReentrantLock lock = new ReentrantLock();

    void m1() {
        lock.lock(); // 相当于 synchronized
        try {
            for (int i = 0; i < 10; i++) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(i);
            }
        } finally {
            lock.unlock(); // 使用完毕后,必须手动释放锁
            // 不同于synchronized,抛出异常后,不会自动释放锁,需要我们在finally中释放此锁
        }
    }

    void m2() {
        lock.lock(); // 相当于 synchronized
        try {
            System.out.println("m2...");
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ReentrantLock2 r1 = new ReentrantLock2();
        new Thread(r1::m1, "t1").start(); // m1 已经执行,被t1占有锁this
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(r1::m2, "t2").start(); // 锁已经被其他线程占用,m1执行完毕后,不会执行
    }

}

2、ReentrantLock 可以进行尝试锁定 tryLock 这样无法锁定、或者在指定时间内无法锁定,线程可以决定是否继续等待。synchronized则必须一直等待,得不到锁就等一直等待。

public class ReentrantLock3 {

    ReentrantLock lock = new ReentrantLock();

    void m1() {
        lock.lock(); // 相当于 synchronized
        try {
            for (int i = 0; i < 10; i++) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(i);
            }
        } finally {
            lock.unlock(); // 使用完毕后,必须手动释放锁
            // 不同于synchronized,抛出异常后,不会自动释放锁,需要我们在finally中释放此锁
        }
    }

    void m2() {
        // 尝试获取锁,返回true拿到了
        if (lock.tryLock()) {
            // lock.tryLock(5, TimeUnit.SECONDS) // 等5s内还没拿到就返回false
            System.out.println("m2...");
        } else {
            System.out.println(" m2 没拿到锁");
        }
        lock.unlock();
    }

    public static void main(String[] args) {
        ReentrantLock3 r1 = new ReentrantLock3();
        new Thread(r1::m1, "t1").start(); // m1 已经执行,被t1占有锁this
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(r1::m2, "t2").start(); // 锁已经被其他线程占用,m1执行完毕后,不会执行
    }

}

3、ReentrantLock 可以调用 lockInterruptibly方法,可以对线程interrupt方法做出响应

/**
 * ReentrantLock 和 synchronized 的区别
 * 
 * ReentrantLock 可以调用 lockInterruptibly方法,可以对线程interrupt方法做出响应
 * 在一个线程等待锁的过程中,可以被interrupt方法打断等待。
 */
public class ReentrantLock4 {

    

    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("t1 start");
                TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);  // 线程一直占用锁
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            
        }, "t1").start();

        Thread t2 = new Thread(() -> {

            try {
                lock.lockInterruptibly(); // t2 尝试获取锁
                System.out.println("t2 start");
            } catch (InterruptedException e) {
                System.out.println("t2 等待中被打断");
            } finally {
                lock.unlock(); // 没有锁定进行unlock就会抛出 IllegalMonitorStateException 
            }
        }, "t2");
        t2.start();

        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 打断线程2的等待
        t2.interrupt();
        
    }

}

4、公平锁

/**
 * ReentrantLock 和 synchronized 的区别
 * <p>
 * ReentrantLock 可以指定为公平锁,synchronized 是不公平锁
 * 公平锁,先获取锁的人,在锁被释放时,优先获得锁
 * 不公平锁,无论先后,线程调度器将会随机给某个线程锁,不用计算线程时序,效率较高
 */
public class ReentrantLock5 extends Thread {

    private static ReentrantLock lock = new ReentrantLock(true);// 指定锁为公平锁

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "获取锁");
            } finally {
                lock.unlock(); // 公平锁 t1 unlock 后,等待时间长的一定是 t2 所以下次一定是 t2 执行
            }
        }
    }

    public static void main(String[] args) {
        ReentrantLock5 r1 = new ReentrantLock5();
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r1);
        t1.start();
        t2.start();
    }
}

 

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务