ProducerConsumerDemo

本文通过使用Java实现并发的生产者消费者模式,详细解释了如何利用线程同步技术来确保线程间的正确交互,具体包括生产者线程如何向共享缓冲区添加元素,以及消费者线程如何从缓冲区中获取元素。文中还展示了实际运行结果,验证了该实现的有效性和正确性。

 

 

package algorithm;

public class ProducerConsumer {
    public static void main(String[] args) {
        SyncStack ss = new SyncStack();

        new Thread(new Producer(ss, "p1")).start();
        new Thread(new Consumer(ss, "c1")).start();
        new Thread(new Producer(ss, "p2")).start();
        new Thread(new Consumer(ss, "c2")).start();
    }
}

class WoTou {
    private int id;

    public WoTou(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public String toString() {
        return "WT" + getId();
    }
}

class SyncStack {
    private int index = 0;
    private WoTou[] arrWT = new WoTou[6];

    public synchronized void push(WoTou wt) {
        while (index == arrWT.length) {
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        }
        this.notifyAll();
        arrWT[index++] = wt;
    }

    public synchronized WoTou pop() {
        while (index == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
            }
        }
        this.notifyAll();
        return arrWT[--index];
    }
}

class Producer implements Runnable {
    private SyncStack ss = null;
    private String name;

    public Producer(SyncStack ss, String name) {
        this.ss = ss;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void run() {
        for (int i = 0; i < 60; i++) {
            WoTou wt = new WoTou(i);
            ss.push(wt);
            System.out.println(getName() + "生产" + wt);
            try {
                Thread.sleep((long) (Math.random() * 100));
            } catch (InterruptedException e) {
            }
        }
    }
}

class Consumer implements Runnable {
    private SyncStack ss = null;
    private String name;

    public Consumer(SyncStack ss, String name) {
        this.ss = ss;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void run() {
        for (int i = 0; i < 60; i++) {
            WoTou wt = ss.pop();
            System.out.println(getName() + "消费" + wt);
            try {
                Thread.sleep((long) (Math.random() * 400));
            } catch (InterruptedException e) {
            }
        }
    }
}


Output:

p1生产WT0
p2生产WT0
c1消费WT0
c2消费WT0
p2生产WT1
p1生产WT1
p2生产WT2
p2生产WT3
p2生产WT4
p2生产WT5
c2消费WT5
p2生产WT6
c1消费WT6
p1生产WT2
c2消费WT2
p1生产WT3
c2消费WT3
p2生产WT7
c1消费WT7
p1生产WT4
c2消费WT4
p1生产WT5
c2消费WT5
p2生产WT8
c1消费WT8
p2生产WT9
c1消费WT9
p1生产WT6
p2生产WT10
c2消费WT6
c1消费WT10
p2生产WT11
p2生产WT12
c2消费WT11
c1消费WT12
p2生产WT13
c2消费WT13
p2生产WT14
c1消费WT14
p1生产WT7
c1消费WT7
p2生产WT15
c2消费WT15
p2生产WT16
p2生产WT17
c2消费WT16
c1消费WT17
p2生产WT18
c2消费WT18
p2生产WT19
p2生产WT20
c1消费WT19
c2消费WT20
p2生产WT21
p1生产WT8
c2消费WT21
p2生产WT22
c2消费WT8
c1消费WT22
p1生产WT9
c2消费WT9
p1生产WT10
c1消费WT10
p1生产WT11
c2消费WT11
p2生产WT23
c2消费WT23
p2生产WT24
c1消费WT24
p1生产WT12
c1消费WT12
p2生产WT25
c2消费WT25
p2生产WT26
p2生产WT27
c1消费WT26
c1消费WT27
p1生产WT13
c1消费WT13
p1生产WT14
c2消费WT14
p2生产WT28
c2消费WT28
p2生产WT29
c1消费WT29
p2生产WT30
c2消费WT30
p2生产WT31
p2生产WT32
c1消费WT31
c2消费WT32
p2生产WT33
c1消费WT33
p2生产WT34
c2消费WT34
p2生产WT35
c1消费WT35
p1生产WT15
c1消费WT15
p1生产WT16
p2生产WT36
c2消费WT16
c2消费WT36
p1生产WT17
c2消费WT17
p2生产WT37
c1消费WT37
p1生产WT18
c1消费WT18
p1生产WT19
c2消费WT19
p1生产WT20
c1消费WT20
p1生产WT21
p1生产WT22
c2消费WT21
c1消费WT22
p1生产WT23
c1消费WT23
p1生产WT24
c2消费WT24
p1生产WT25
c2消费WT25
p2生产WT38
p1生产WT26
c2消费WT38
c2消费WT26
p1生产WT27
c2消费WT27
p1生产WT28
c1消费WT28
p1生产WT29
c2消费WT29
p1生产WT30
c2消费WT30
p1生产WT31
c1消费WT31
p1生产WT32
c2消费WT32
p1生产WT33
c1消费WT33
p1生产WT34
p2生产WT39
c2消费WT34
c2消费WT39
p1生产WT35
p1生产WT36
c1消费WT35
p2生产WT40
c2消费WT36
p2生产WT41
c2消费WT40
c2消费WT41
p2生产WT42
c1消费WT42
p2生产WT43
p1生产WT37
c1消费WT43
p1生产WT38
c2消费WT37
c1消费WT38
p2生产WT44
c2消费WT44
p2生产WT45
c1消费WT45
p2生产WT46
c1消费WT46
p2生产WT47
c2消费WT47
p2生产WT48
c1消费WT48
p1生产WT39
c1消费WT39
p2生产WT49
c2消费WT49
p2生产WT50

http://ixhong.iteye.com/blog/2228623

 

转载于:https://www.cnblogs.com/softidea/p/4660363.html

<think>我们讨论的是在Java中,使用锁对象(Lock)来调用线程通信的方法。在Java中,除了使用synchronized关键字和对象的wait()、notify()、notifyAll()方法进行线程通信外,还可以使用java.util.concurrent.locks包中的Lock和Condition接口来实现更灵活的线程通信。具体来说,Lock替代了synchronized,而Condition替代了对象监视器方法(wait,notify,notifyAll)。Condition接口提供了await()、signal()和signalAll()方法,分别对应于wait()、notify()和notifyAll()。使用Lock和Condition的基本步骤:1.创建一个Lock对象(如ReentrantLock)。2.通过Lock对象获取一个或多个Condition对象。3.在需要等待某个条件的地方,使用Condition的await()方法。4.当条件满足时,使用Condition的signal()或signalAll()方法唤醒等待的线程。下面给出一个例子:生产者-消费者模型。在这个模型中,生产者生产物品,消费者消费物品。当物品队列满时,生产者等待;当物品队列空时,消费者等待。我们使用Lock和Condition来实现线程间的通信。代码示例:</think>### 锁对象调用线程通信方法详解 在Java中,使用锁对象(`Lock`)进行线程通信主要通过`Condition`接口实现,它比`synchronized`的`wait/notify`更灵活。`Condition`提供了`await()`、`signal()`和`signalAll()`方法,支持多条件等待集,适用于复杂的线程协作场景。 #### 示例:生产者-消费者模型 ```java import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ProducerConsumerDemo { private final Queue<Integer> queue = new LinkedList<>(); private final int maxSize = 5; private final Lock lock = new ReentrantLock(); private final Condition notFull = lock.newCondition(); // 队列未满条件 private final Condition notEmpty = lock.newCondition(); // 队列非空条件 // 生产者方法 public void produce(int value) throws InterruptedException { lock.lock(); // 获取锁 try { // 队列满时等待 while (queue.size() == maxSize) { System.out.println("队列已满,生产者等待"); notFull.await(); // 释放锁并等待 } queue.add(value); System.out.println("生产: " + value); notEmpty.signal(); // 唤醒消费者 } finally { lock.unlock(); // 确保锁释放 } } // 消费者方法 public void consume() throws InterruptedException { lock.lock(); try { // 队列空时等待 while (queue.isEmpty()) { System.out.println("队列为空,消费者等待"); notEmpty.await(); // 释放锁并等待 } int value = queue.remove(); System.out.println("消费: " + value); notFull.signal(); // 唤醒生产者 } finally { lock.unlock(); } } public static void main(String[] args) { ProducerConsumerDemo pc = new ProducerConsumerDemo(); // 生产者线程 new Thread(() -> { for (int i = 0; i < 10; i++) { try { pc.produce(i); Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }).start(); // 消费者线程 new Thread(() -> { for (int i = 0; i < 10; i++) { try { pc.consume(); Thread.sleep(250); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }).start(); } } ``` #### 代码解释: 1. **锁与条件变量** - `ReentrantLock` 提供显式锁控制 - 两个`Condition`对象: `notFull`(队列未满时唤醒生产者) `notEmpty`(队列非空时唤醒消费者) 2. **关键方法** - `await()`:释放锁并阻塞,直到被`signal()`唤醒 - `signal()`:唤醒一个等待线程(不保证公平性) - `signalAll()`:唤醒所有等待线程 3. **执行流程** - 生产者检查队列满 → 调用`notFull.await()`挂起 - 消费者取出数据 → 调用`notFull.signal()`唤醒生产者 - 消费者检查队列空 → 调用`notEmpty.await()`挂起 - 生产者添加数据 → 调用`notEmpty.signal()`唤醒消费者 4. **重要细节** - 使用`while`而非`if`检查条件(避免虚假唤醒) - `lock.lock()`/`unlock()`必须放在`try-finally`中确保锁释放 - 条件变量需从同一锁对象创建 #### 对比 synchronized | 特性 | Lock + Condition | synchronized | |--------------------|------------------------|-----------------------| | 多条件等待 | ✅ (多个Condition) | ❌ (单一等待集) | | 公平锁 | ✅ (ReentrantLock可选) | ❌ | | 超时等待 | ✅ (awaitNanos等方法) | ❌ | | 可中断等待 | ✅ | ❌ | #### 最佳实践 1. **避免嵌套锁**:防止死锁 2. **及时解锁**:`finally`块中必须调用`unlock()` 3. **精确唤醒**:为不同条件创建独立`Condition`对象 4. **性能敏感场景**:`Lock`通常比`synchronized`性能更高 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值