本文主要讲解使用synchronized与ReentrantLock和Condition实现生产消费者的区别。
一、synchronized简介
Java程序依靠synchronized对线程进行同步。所以首先了解下synchronized的作用:
关键字 synchronized 可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一时刻,只能有一个线程处于方法或同步块中,它保证了线程对变量访问的可见性和排他性。
- 对于普通同步方法,锁是当前实例对象
- 对于静态同步方法,锁是当前类的 Class 对象
- 对于同步方法块,锁是 Synchonized 括号里配置的对象
使用ReentrantLock比直接使用synchronized更安全,可以替代synchronized进行线程同步。
二、ReentrantLock介绍
顾名思义,ReentrantLock是可重入锁,它和synchronized一样,一个线程可以多次获取同一个锁。Java语言直接提供了synchronized关键字用于加锁,但这种锁一是很重,二是获取时必须一直等待,没有额外的尝试机制。java.util.concurrent.locks包提供的ReentrantLock用于替代synchronized加锁。
三、代码示例
package org.thread;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* 2022/11/24
* 用synchronized实现的功能通过ReentrantLock和Condition来实现.
* 使用Condition对象来实现wait和notify的功能。
* @author Gerry
* @version 1.0
*/
public class ConditionDemo {
/**
* 1.lock不再用synchronize把同步代码包装起来;
* 2.阻塞需要另外一个对象condition;
* 3.同步和唤醒的对象是condition而不是lock,对应的方法是await和signal,而不是wait和notify。
*
* 为什么需要使用condition呢?简单一句话,lock更灵活。以前的方式只能有一个等待队列,在实际应用时可能需要多个,
* 比如读和写。为了这个灵活性,lock将同步互斥控制和等待队列分离开来,
* 互斥保证在某个时刻只有一个线程访问临界区(lock自己完成),等待队列负责保存被阻塞的线程(condition完成)。
*/
private final ReentrantLock lock = new ReentrantLock();
//使用Condition时,引用的Condition对象必须从Lock实例的newCondition()返回,
// 这样才能获得一个绑定了Lock实例的Condition实例
//通过查看ReentrantLock的源代码发现,condition其实是等待队列的一个管理者,condition确保阻塞的对象按顺序被唤醒。
private final Condition condition = lock.newCondition();
private Queue<String> queue = new LinkedList<>();
public void addTask(String s) {
lock.lock();
try {
queue.add(s);
condition.signal();
} finally {
//最后一定要释放
lock.unlock();
}
}
public String getTask() throws InterruptedException{
lock.lock();
try {
while (queue.isEmpty()) {
condition.await();
}
return queue.remove();
} finally {
//最后一定要释放
lock.unlock();
}
}
/**
* -- 旧的方式:--
* 线程consumer
* synchronize(obj){
* obj.wait();//没东西了,等待
* }
*
* 线程producer
* synchronize(obj){
* obj.notify();//有东西了,唤醒
* }
*
* -- 新的方式:--
* //生产
* lock.lock();
* condition.await();
* lock.unlock();
*
* //消费
* lock.lock();
* condition.signal();
* lock.unlock();
*/
}