java同步示例 生产与消费_面试题:Java并发编程生产者和消费者有序消费问题

本文介绍了如何解决并发编程中的资源有序生产消费问题,提出了两种解决方案:一是利用synchronized关键字和Object的监听器,二是采用java.util.concurrent.locks.Lock和Condition接口。通过示例代码详细解析了两种方法的实现过程,展示了如何通过标志变量控制生产与消费的顺序,确保线程间的协调与同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

摘要:对于一个资源对象,必须先生产再消费,消费后再生产,如此循环往复。为了解决这个并发问题,提供两种解决方案,一是使用synchronized关键字和Object对象的监听器,二是使用java.util.concurrent.locks下的类Lock和Condition。

§前言

定义一个实体类,名为资源,它有两个属性,分别是姓名和性别。兹有两个线程, 一个是生产者,负责给资源实例的姓名和性别赋值,一个是消费者,负责打印资源实例的姓名和性别的值。

要求:有序生产和消费资源,即对于一个资源对象,必须先生产-消费-生产-消费,如此循环往复;当然了,第一个操作可能是消费者,这是没有资源可以消费的。

解决问题:生产者对资源对象赋值后进入等待状态,并唤醒消费者输出资源属性,输出后立刻唤醒生产者。一般要加入个标志进行辅助,判断能否生产或者消费。

§案例分析

有两个解决方案,一是使用synchronized关键字,二是使用java.util.concurrent.locks下的类Lock和Condition。两个方案都需要加入一个标志,标记当前是否允许打印或者赋值。

§使用同步锁synchronized关键字

package com.eg.wiener.conccurrency;

/**

* 妖的出现,有序打印字符串信息

*/

class Resource {

/* 姓名 */

private String name;

/* 性别 */

private String sex;

//标记一个操作单元是否完成,true 是

private boolean flag = false;

//赋值功能。

public synchronized void set(String name, String sex) {

if (flag) {

try {

// 赋值函数进入等待状态

this.wait();

} catch (InterruptedException e) {

}

}

this.name = name;

this.sex = sex;

flag = true;

// 赋值结束,唤醒打印函数

this.notify();

}

/**

* 消费者,获取资源属性

*/

public synchronized void out() {

if (!flag)

try {

//进入等待状态,停止打印

this.wait();

} catch (InterruptedException e) {

}

System.out.println(name + "------" + sex);

flag = false;

//打印结束,唤醒资源赋值函数

this.notify();

}

}

//生产者,赋值线程任务

class Input implements Runnable {

private Resource r;

//任务一初始化就必须有要处理的资源。

Input(Resource r) {

this.r = r;

}

// 赋值

public void run() {

int x = 0;

while (true) {

if (x == 0) {

r.set("张飞", "男");

} else {

r.set("rose", "女女女女");

}

//根据取模结果实现切换

x = (x + 1) % 2;

}

}

}

//获取值线程任务

class Output implements Runnable {

private Resource r;

Output(Resource r) {

this.r = r;

}

public void run() {

while (true) {

r.out();

}

}

}

public class ThreadTest2_3 {

public static void main(String[] args) {

Resource r = new Resource();

Input in = new Input(r);

Output out = new Output(r);

Thread t1 = new Thread(in);

Thread t2 = new Thread(out);

t1.start();

t2.start();

}

}

实现方案分析:通过synchronized关键字锁定同一个资源(记住 currentRes)后,定义标记flag,由flag的值决定打印或者赋值操作是否允许,不允许的时候就调用currentRes的wait函数,让出CPU执行权,唤醒另一个操作。

§使用JUC的Lock和Condition

在 Condition 对象中,await、signal 和 signalAll三个方法分别对应于 Object实例的三个监视器方法 wait、notify 和 notifyAll。Condition 接口与 Lock 配合实现了等待/通知模式,要为某个 Lock 对象(例如 aLock)获得 Condition 对象,需要aLock调用函数newCondition() 。

package com.eg.wiener.conccurrency;

import java.util.concurrent.locks.*;

/**

* 程序改成JDK1.5的Lock Condition接口

*/

class Resource {

private String name;

private String sex;

//定义标记

private boolean flag = false;

//先创建锁对象

private final Lock lock = new ReentrantLock();

//通过锁对象获取监视器对象

private Condition con = lock.newCondition();

//赋值功能

public void set(String name, String sex) {

lock.lock();

try {

if (flag) {

try {

//     该线程将释放锁、节点加入等待队列进入等待状态

con.await();

} catch (InterruptedException e) {

}

}

this.name = name;

this.sex = sex;

flag = true;

con.signal();

} finally {

lock.unlock();

}

}

//获取值

public void out() {

lock.lock();

try {

if (!flag) {

try {

con.await();

} catch (InterruptedException e) {

}

}

System.out.println(name + "------" + sex);

flag = false;

con.signal();

} finally {

lock.unlock();

}

}

}

//赋值线程任务

class Input implements Runnable {

private Resource r;

//任务一初始化就必须有要处理的资源

Input(Resource r) {

this.r = r;

}

public void run() {

int x = 0;

while (true) {

if (x == 0) {

r.set("张飞", "男");

} else {

r.set("rose", "女女女女");

}

x = (x + 1) % 2;

}

}

}

//获取值线程任务

class Output implements Runnable {

private Resource r;

Output(Resource r) {

this.r = r;

}

public void run() {

while (true) {

r.out();

}

}

}

public class ThreadTest2_4 {

public static void main(String[] args) {

Resource r = new Resource();

Input in = new Input(r);

Output out = new Output(r);

Thread t1 = new Thread(in);

Thread t2 = new Thread(out);

t1.start();

t2.start();

}

}

§小结

文章到这里就结束了,看完之后你有什么想法想要跟大家分享呢?评论区在等着你!

§Reference

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值