Java多线程并发之锁对象ReentrantLock和条件对象Condition

ReentrantLock被称为显示锁,synchronized被称为隐式锁。

ReentrantLock和Condition是在java 1.5中才出现的,它们用来替代传统的synchronized 、wait()、notify()来实现线程间的协作,相比使用synchronized,使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。

ReentrantLock

ReentrantLock实现了Lock接口。

用 ReentrantLock 保护代码块的基本结构如下:

myLock.lock();  // a ReentrantLock object
try
{
	critical section   //临界区代码
}
finally
{
	myLock.unlock(); // make sure the lock is unlocked even if an exception is thrown
}

这一结构确保任何时刻只有一个线程进人临界区。一旦一个线程封锁了锁对象, 其他任何线程都无法通过 lock 语句。当其他线程调用 lock 时,它们被阻塞,直到第一个线程释放锁对象。

Condition

  • Condition是个接口,基本的方法就是await()和signal()方法;
  • Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()
  • 调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用
  • Condition中的await()对应Object的wait();
    Condition中的signal()对应Object的notify();
    Condition中的signalAll()对应Object的notifyAll()。

ReentrantLock 和 synchronized都是可重入锁

可重入锁也叫递归锁,同一线程在外层方法获取锁的时候,再进入内层方法会自动获取锁,也就是说,线程可以进入任何一个它已经拥有的锁所同步着的代码块。
看下例子就很好理解:
(1). 基于 synchronized

public class ReentrantLockTest {
    public static void main(String[] args) {
        Phone phone = new Phone();
        // 第一个线程
        new Thread(() -> {
            phone.sendMsg();
        }, "t1").start();
        // 第二个线程
        new Thread(() -> {
            phone.sendMsg();
        }, "t2").start();
    }
}

class Phone {
    // 发送短信同步方法
    public synchronized void sendMsg() {
        System.out.println(Thread.currentThread().getName() + " called sendMsg()");
        // 进入另外一个同步着的方法
        sendEmail();
    }
    // 发送邮件同步方法
    public synchronized void sendEmail() {
        System.out.println(Thread.currentThread().getName() + " ******called sendEmail()");
    }
}

运行结果:

t1 called sendMsg()             // t1线程在外层方法获取锁的时候
t1 ******called sendEmail()     // t1再进入内层方法会自动获取锁
t2 called sendMsg()
t2 ******called sendEmail()

(2). 基于 ReentrantLock

public class ReentrantLockTest {
    public static void main(String[] args) {
        Phone phone = new Phone();
        // 第一个线程
        Thread t1 = new Thread(phone, "t1");
        // 第二个线程
        Thread t2 = new Thread(phone, "t2");

        t1.start();
        t2.start();
    }
}

class Phone implements Runnable {
    ReentrantLock lock = new ReentrantLock();
    // 发送短信方法
    public void sendMsg() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " called sendMsg()");
            // 进入另一个方法
            sendEmail();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    // 发送邮件方法
    public void sendEmail() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " ******called sendEmail()");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void run() {
        sendMsg();
    }
}

运行结果:

t1 called sendMsg()             // t1线程在外层方法获取锁的时候
t1 ******called sendEmail()     // t1再进入内层方法会自动获取锁
t2 called sendMsg()
t2 ******called sendEmail()
发布了516 篇原创文章 · 获赞 89 · 访问量 73万+

猜你喜欢

转载自blog.csdn.net/yzpbright/article/details/104644211