- 在一个生产环境中,生产者和消费者在同一时间段内共享同一块缓冲区,生产者负责向缓冲区中添加数据,消费者负责从缓冲区中取出数据,生产者消费者模式本质是为了实现线程通信。
一、实现多线程的优雅代码(lambda表达式)
简单的一句即可(Java8的新特性)。
new Thread(() -> System.out.println("多线程任务执行!")).start(); // 启动线程
举例:
public class Test {
public static void main(String[] args) {
Account account = new Account();
//lambda表达式
new Thread(()->{
account.count();
},"A").start();
new Thread(()->{
account.count();
},"B").start();
}
}
//待访问的公共资源
class Account{
private static int num;
public synchronized void count(){
num++;
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"是第"+num+"位访客");
}
}
二、Synchronized锁实现
/**
* @description: 生产者消费者模型 Synchronized锁实现
* @author: Liu Wen
* @create: 2020-03-10 22:26
**/
public class ProductConsumerSynchronized {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 30; i++) {
data.increment();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
data.decrement();
}
},"B").start();
}
//内部类定义资源
static class Data{
private Integer num = 0;
/**
* 加一
*/
public synchronized void increment(){
while (num!=0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num++;
this.notify();
System.out.println(Thread.currentThread().getName()+"--->"+num);
}
/**
* 减一
*/
public synchronized void decrement(){
//当num==0,不要再减
while(num == 0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num--;
this.notify();
System.out.println(Thread.currentThread().getName()+"--->"+num);
}
}
}
注意:判断的时候必须使用 while 循环,而不能使用 if,因为使用 if 会存在线程虚假唤醒的问题,虚假唤醒是指 wait 会在除了 notify 以外的情况被唤醒,而此时是不应该被唤醒的,使用 while 可以多次检测,避免虚假唤醒的问题。
三、Lock锁实现
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @description: 生产者消费者模型 Lock锁实现
* @author: Liu Wen
* @create: 2020-03-10 22:28
**/
public class ProductConsumerLock {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for (int i = 0; i < 30; i++) {
data.increment();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
data.decrement();
}
},"B").start();
}
//内部类实现资源
static class Data{
private Integer num = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
/**
* 加一
*/
public void increment() {
try {
lock.lock(); //加锁
while (num != 0) {
condition.await(); //condition条件等待
}
num++;
condition.signal(); //condition条件唤醒
System.out.println(Thread.currentThread().getName() + "--->" + num);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock(); //释放锁
}
}
/**
* 减一
*/
public void decrement() {
try {
lock.lock();
while (num == 0) {
condition.await();
}
num--;
condition.signal();
System.out.println(Thread.currentThread().getName() + "--->" + num);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
Condition 接口也提供了类似 Object 的监视方法,与 Lock 配合可以实现等待/通知模式,Condition 对象依赖于 Lock 对象的。