一句话导读
ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源重复加锁,即当前线程获取该锁再次获取不会被阻塞。在java关键字synchronized隐式支持重入性,synchronized通过获取自增,释放自减的方式实现重入。与此同时,ReentrantLock还支持公平锁和非公平锁两种方式。
目录
下面我们了解下如何通过ReentrantLock实现生产者和消费者模式吧,线程间的交互需要用到Condition的await、signal;
一、首先定义生产者
1.变量定义
在变量定义的时候,首先定义了一个容器和这个容器的上限:List breads; int maxSize;生产好的面包则放到breads中,达到上限maxSize则停止生产。另外定义了一个锁ReentrantLock lock,在线程操作breads的时候,需要通过lock来做到互斥。通过定义两个锁信号来做到线程间的通讯,当容器满了在Condition full需要等待。当容器空了,则Condition empty进入等待
2.生产面包方法
首先获取锁lock.lock();然后判断容器breads是否满了,如果满了则当前线程等待full.await();如果容器没有满,则可以生成面包,breads.add(bread);并且唤醒消费者empty.signalAll();
3.线程接口实现
通过Runnable接口,实现run方法,循环调用生产面包方法
import com.rainy.distributlock.producerAndConsumer.Bread;
import com.rainy.distributlock.producerAndConsumer.blockingQueue.BreadStore;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* 生产者
*/
public class Producer implements Runnable {
//锁
private ReentrantLock lock;
//容器满了的信号
private Condition full;
//容器空了的信号
private Condition empty;
//容器
private List<Bread> breads;
//容器最大容量
private int maxSize;
//计数器
private AtomicInteger count = new AtomicInteger(0);
//构造方法
public Producer(ReentrantLock lock, Condition full, Condition empty, List<Bread> breads, int maxSize) {
this.lock = lock;
this.full = full;
this.empty = empty;
this.breads = breads;
this.maxSize = maxSize;
}
//生产面包
public void produce() {
//获取锁
lock.lock();
try {
//如果容器满了,等待
if (breads.size() == maxSize) {
//当前线程等待
System.out.println(Thread.currentThread().getName() + "容器已满,等待");
full.await();
System.out.println(Thread.currentThread().getName() + "生产面包被唤醒");
//没有满则生产面包
}else {
Bread bread = new Bread(UUID.randomUUID().toString(), Thread.currentThread().getName() + "-" + count.getAndIncrement());
breads.add(bread);
System.out.println(Thread.currentThread().getName() + "生产了面包:" + bread);
//唤醒等待的消费者
empty.signalAll();
// Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + "释放锁");
lock.unlock();
}
}
@Override
public void run() {
while (true) {
produce();
}
}
}
二、其次定义消费者
1.变量的定义
定义锁、信号条件以及容器。通过构造方法,将变量的值初始化,生产者的变了也是通过构造方法初始化的,这样就可以将所有的变量共享了
2.消费面包的方法
首先获取锁lock.lock();当容器为空的时候breads.isEmpty(),则不能再消费,消费线程等待,empty.await();当容器不为空,则获取面包并从容器中移除,breads.remove(0);并发出继续生产面包的信号:full.signalAll();
3.实现线程接口
通过Runnable接口实现run方法,循环调用消费面包方法
import com.rainy.distributlock.producerAndConsumer.Bread;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Consumer implements Runnable {
private ReentrantLock lock;
private Condition full;
private Condition empty;
private List<Bread> breads;
//构造方法
public Consumer(ReentrantLock lock, Condition full, Condition empty, List<Bread> breads) {
this.lock = lock;
this.full = full;
this.empty = empty;
this.breads = breads;
}
//生产面包
public void consumer() {
lock.lock();
try {
if (breads.isEmpty()) {
System.out.println("没有面包了");
empty.await();
System.out.println("开始生产面包");
} else {
Bread bread = breads.remove(0);
System.out.println(Thread.currentThread().getName() + "-" + bread.getName());
full.signalAll();
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
@Override
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + "释放锁");
consumer();
}
}
}
三、最后定义主方法
首先定义共享变量,锁ReentrantLock reentrantLock;容器List list;最大容量 int maxSIze; 容器满条件Condition full;容器空条件Condition empty;
然后定义生产者线程,并将变量赋值到到生产者中
再定义两个消费者线程,并将变量赋值到消费者中
最后启动各个线程,即可实现生产者和消费者模式了。
import com.rainy.distributlock.producerAndConsumer.Bread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class MainProcess {
public static void main(String[] args) {
ReentrantLock reentrantLock = new ReentrantLock();
List<Bread> list = new ArrayList<>();
int maxSize = 100;
Condition full = reentrantLock.newCondition();
Condition empty = reentrantLock.newCondition();
Producer producer = new Producer(reentrantLock,full,empty,list,maxSize);
Thread producerThread = new Thread(producer);
producerThread.setName("生产者");
producerThread.start();
Consumer consumer = new Consumer(reentrantLock,full,empty,list);
Thread consumerThread = new Thread(consumer);
consumerThread.setName("消费者1");
consumerThread.start();
Consumer consumer2 = new Consumer(reentrantLock,full,empty,list);
Thread consumerThread2 = new Thread(consumer2);
consumerThread2.setName("消费者2");
consumerThread2.start();
}
}