JUC-Condition线程通信

本文介绍如何利用Java并发包中的Lock接口和Condition接口实现生产者消费者模式。文章详细展示了Lock与Condition在生产者消费者场景中的具体应用,并通过代码示例解释了如何正确使用await和signal方法。

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

1,Codition接口描述了可能会与锁有关联的条件变量。这些变量在用法上与使用Object.wait访问的隐式监视器类似。

但提供了更强大的功能,需要指出的是,单个lock可能与多个condition对象关联。为了避免兼容性问题,condition方法的名称与对应的object版本中不一样。

2,在condition对象中,与wait,notify,notifyAll方法对应的分别是await,signal,和signalAll。

3,condition实例实质上是被绑定到了一个锁上,要为特定Lock实例获得condition实例,请使用newCondition()方法。

 

针对上一节中使用synchronized和wait方法处理的生产者与消费者程序中,这里通过Lock和condition来联合处理。

要实现Lock和Condition处理,必须先实力化两个对象。

实例化Lock对象:

private Lock lock = new ReentrantLock();

实例化Condition对象:通过Lock对象的newCondition方法实例化,来获得Lock的锁,从而实现与Lock锁通信,进行唤醒,等待操作

private Condition condition = lock.newCondition();

代码:

注意:await方法上一节的wait方法一致,需要放到while循环里面,避免被唤醒后条件不满足也继续执行。

package com.atguigu.juc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*
 * 生产者消费者案例:
 */
public class TestProductorAndConsumerForLock {

    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Productor pro = new Productor(clerk);
        Consumer con = new Consumer(clerk);

        new Thread(pro, "生产者 A").start();
        new Thread(con, "消费者 B").start();

         new Thread(pro, "生产者 C").start();
         new Thread(con, "消费者 D").start();
    }
}

class Clerk {
    private int product = 0;

    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    // 进货
    public void get() {
lock.lock();
try { while (product >= 1) { // 为了避免虚假唤醒,应该总是使用在循环中。 System.out.println("产品已满!"); try { condition.await(); } catch (InterruptedException e) { } } System.out.println(Thread.currentThread().getName() + " : " + ++product); condition.signalAll(); } finally { lock.unlock(); } } // 卖货 public void sale() { lock.lock(); try { while (product <= 0) { System.out.println("缺货!"); try { condition.await(); } catch (InterruptedException e) { } } System.out.println(Thread.currentThread().getName() + " : " + --product); condition.signalAll(); } finally { lock.unlock(); } } } // 生产者 class Productor implements Runnable { private Clerk clerk; public Productor(Clerk clerk) { this.clerk = clerk; } @Override public void run() { for (int i = 0; i < 20; i++) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } clerk.get(); } } } // 消费者 class Consumer implements Runnable { private Clerk clerk; public Consumer(Clerk clerk) { this.clerk = clerk; } @Override public void run() { for (int i = 0; i < 20; i++) { clerk.sale(); } } }

执行结果:

正常执行

 

<think>我们被要求解释“线程通信”,并按照格式输出回答和相关问题。 线程通信指的是多个线程之间交换信息或协调行动的过程。在Java中,常见的线程通信方式包括共享内存、消息传递、等待/通知机制等。 我们将分点详细解释,并给出代码示例。最后,按照要求提出3-5个相关问题。 注意:回答必须使用中文,并在最后输出“§§相关问题§§”以及相关问题。 计划结构: 1. 线程通信概述 2. 主要通信方式(共享内存、等待/通知、管道流、CountDownLatch等) 3. 代码示例(重点展示等待/通知机制) 4. 注意事项 5. 相关问题 由于要求禁止换行分散,我们将相关问题和代码示例都整合在回答中,但保持清晰。</think>### Java 线程通信详解 线程通信指多线程间**协调执行顺序**或**传递数据**的机制。核心目标是解决并发环境下的**资源竞争**和**执行依赖**问题。以下是主流实现方式--- #### 一、共享内存(隐式通信) 通过共享变量实现数据传递,需配合同步机制: ```java // 示例:基于 volatile 的可见性通信 public class SharedMemoryDemo { private volatile boolean flag = false; // 保证多线程可见性 public void producer() { // ... 生产数据 flag = true; // 通知消费者 } public void consumer() { while (!flag) { /* 循环等待通知 */ } // ... 消费数据 } } ``` **适用场景**:数据交换频繁但竞争不激烈的场景 --- #### 二、等待/通知机制(显式通信) 通过 `Object` 的 `wait()/notify()` 实现精准控制: ```java synchronized (lock) { while (!condition) { lock.wait(); // 释放锁并等待 } // 条件满足后执行任务 lock.notifyAll(); // 唤醒所有等待线程 } ``` **特点**: - `wait()` 会释放对象锁,`sleep()` 不会 - 必须先获得锁才能调用(在 `synchronized` 块内) - 推荐用 `while` 代替 `if` 检查条件(防虚假唤醒) --- #### 三、JUC 工具类通信 1. **`BlockingQueue` (阻塞队列)** ```java BlockingQueue<String> queue = new ArrayBlockingQueue<>(10); // 生产者 queue.put("data"); // 队列满时自动阻塞 // 消费者 String data = queue.take(); // 队列空时自动阻塞 ``` 2. **`CountDownLatch` (倒计时门闩)** ```java CountDownLatch latch = new CountDownLatch(3); // 工作线程 new Thread(() -> { doWork(); latch.countDown(); // 计数减1 }).start(); latch.await(); // 主线程等待计数归零 ``` 3. **`CyclicBarrier` (循环栅栏)** ```java CyclicBarrier barrier = new CyclicBarrier(3); new Thread(() -> { doWork(); barrier.await(); // 等待所有线程到达 }).start(); ``` --- #### 四、管道通信(`PipedInputStream/PipedOutputStream`) 定向数据传输: ```java PipedInputStream pis = new PipedInputStream(); PipedOutputStream pos = new PipedOutputStream(pis); // 线程A写入数据 pos.write("Hello".getBytes()); // 线程B读取数据 byte[] buffer = new byte[10]; pis.read(buffer); // 阻塞直到数据到达 ``` --- ### ⚠️ 通信原则 1. **避免忙等待**:用 `wait/notify` 替代 `while(flag)` 空循环 2. **优先使用 JUC 工具**:比 `synchronized + wait/notify` 更安全高效 3. **预防死锁**:确保锁的获取顺序一致 4. **线程可见性**:共享变量必须用 `volatile` 或原子类保证可见性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值