Loading [MathJax]/jax/output/CommonHTML/config.js
部署DeepSeek模型,进群交流最in玩法!
立即加群
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Java】实现生产者消费者模型

【Java】实现生产者消费者模型

作者头像
后端码匠
发布于 2023-02-27 01:15:37
发布于 2023-02-27 01:15:37
86800
代码可运行
举报
文章被收录于专栏:后端码匠后端码匠
运行总次数:0
代码可运行

【Java】生产者消费者模型

0x1 前言

生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加产品,消费者从存储空间中取走产品,当存储空间为空时,消费者阻塞,当存储空间满时,生产者阻塞。

0x2 实现

以下用4种方式来实现生产者消费者模型

0x21 wait()和notify()方法

这也是最简单最基础的实现,缓冲区满和为空时都调用wait()方法等待,当生产者生产了一个产品或者消费者消费了一个产品之后会唤醒所有线程。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.com.codingce.juc.生产者消费者模型;

import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 生产者和消费者, wait()和notify()方式实现
 * <p>
 * 后端码匠
 *
 * @author mxz
 */
public class WaitNotifyExample {

    private static Integer count = 0;
    private static final Integer maxCount = 10;
    private final Object LOCK = new Object();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService service = Executors.newCachedThreadPool();
        WaitNotifyExample example = new WaitNotifyExample();
        service.execute(example.new Producer());
        service.execute(example.new Producer());
        service.execute(example.new Consumer());
        service.shutdown();
        System.out.println(service.awaitTermination(10L, TimeUnit.SECONDS));
    }

    class Producer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(2000L);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized (LOCK) {
                    // 缓冲区满调用wait()方法等待
                    while (Objects.equals(count, maxCount)) {
                        try {
                            LOCK.wait();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    count++;
                    System.out.println("*************** " + Thread.currentThread().getName() + ", 生产者生产, 目前总共有: " + count + " ***************");
                    LOCK.notifyAll();
                }
            }
        }
    }

    class Consumer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(2000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (LOCK) {
                    // 缓冲区为空调用wait()方法等待
                    while (count == 0) {
                        try {
                            LOCK.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    count--;
                    System.out.println("--------------- " + Thread.currentThread().getName() + ", 消费者消费, 目前总共有: " + count + " ---------------");
                    LOCK.notifyAll();
                }
            }
        }
    }
    
}

output

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
*************** pool-1-thread-2, 生产者生产, 目前总共有: 1 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 0 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 0 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 2 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 3 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 2 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 3 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 4 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 3 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 4 ***************
false
*************** pool-1-thread-1, 生产者生产, 目前总共有: 5 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 6 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 5 ---------------
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 4 ---------------
*************** pool-1-thread-2, 生产者生产, 目前总共有: 5 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 6 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 7 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 6 ---------------
*************** pool-1-thread-2, 生产者生产, 目前总共有: 7 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 8 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 7 ---------------
*************** pool-1-thread-2, 生产者生产, 目前总共有: 8 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 9 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 10 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 9 ---------------
*************** pool-1-thread-2, 生产者生产, 目前总共有: 10 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 9 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 10 ***************

0x22 可重入锁ReentrantLock

java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,通过对locklock()方法和unlock()方法实现了对锁的显示控制,而synchronize()则是对锁的隐性控制。 可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响,简单来说,该锁维护这一个与获取锁相关的计数器,如果拥有锁的某个线程再次得到锁,那么获取计数器就加1,函数调用结束计数器就减1,然后锁需要被释放两次才能获得真正释放。已经获取锁的线程进入其他需要相同锁的同步代码块不会被阻塞。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.com.codingce.juc.生产者消费者模型;

import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 生产者和消费者, {@link ReentrantLock} 方式实现
 * <p>
 * 后端码匠
 *
 * @author mxz
 */
public class ReentrantLockExample {

    private static Integer count = 0;
    private static final Integer maxCount = 10;
    // 创建一个锁对象
    private final Lock lock = new ReentrantLock();
    // 使用 Condition 对象来实现 wait 和 notify 的功能
    // 创建两个条件变量, 一个为缓冲区非满, 一个为缓冲区非空
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService service = Executors.newCachedThreadPool();
        ReentrantLockExample example = new ReentrantLockExample();
        service.execute(example.new Producer());
        service.execute(example.new Consumer());
        service.shutdown();
        System.out.println(service.awaitTermination(15L, TimeUnit.SECONDS));
    }

    class Producer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000L);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // 获取锁
                lock.lock();
                try {
                    while (Objects.equals(count, maxCount)) {
                        try {
                            notFull.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    count++;
                    System.out.println("*************** " + Thread.currentThread().getName() + ", 生产者生产, 目前总共有: " + count + " ***************");
                    // 唤醒消费者
                    notEmpty.signal();
                } finally {
                    // 释放锁
                    lock.unlock();
                }
            }
        }
    }

    class Consumer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                lock.lock();
                try {
                    while (count == 0) {
                        try {
                            notEmpty.await();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    count--;
                    System.out.println("--------------- " + Thread.currentThread().getName() + ", 消费者消费, 目前总共有: " + count + " ---------------");
                    notFull.signal();
                } finally {
                    lock.unlock();
                }
            }
        }
    }

}

output

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
--------------- pool-1-thread-2, 消费者消费, 目前总共有: 0 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
--------------- pool-1-thread-2, 消费者消费, 目前总共有: 0 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
--------------- pool-1-thread-2, 消费者消费, 目前总共有: 0 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
--------------- pool-1-thread-2, 消费者消费, 目前总共有: 0 ---------------
false
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
--------------- pool-1-thread-2, 消费者消费, 目前总共有: 0 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
--------------- pool-1-thread-2, 消费者消费, 目前总共有: 0 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
--------------- pool-1-thread-2, 消费者消费, 目前总共有: 0 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
--------------- pool-1-thread-2, 消费者消费, 目前总共有: 0 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
--------------- pool-1-thread-2, 消费者消费, 目前总共有: 0 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
--------------- pool-1-thread-2, 消费者消费, 目前总共有: 0 ---------------

0x23 阻塞队列BlockingQueue

BlockingQueue阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种:

  • 当队列满了的时候进行入队列操作;
  • 当队列空了的时候进行出队列操作。

因此,当一个线程对已经满了的阻塞队列进行入队操作时会阻塞,除非有另外一个线程进行了出队操作,当一个线程对一个空的阻塞队列进行出队操作时也会阻塞,除非有另外一个线程进行了入队操作。从上可知,阻塞队列是线程安全的。 下面是BlockingQueue接口的一些方法:

操作

抛异常

特定值

阻塞

超时

插入

add(o)

offer(o)

put(o)

offer(o, timeout, timeunit)

移除

remove(o)

poll(o)

take(o)

poll(timeout, timeunit)

检查

element(o)

peek(o)

这四类方法分别对应的是:

  • ThrowsException:如果操作不能马上进行,则抛出异常;
  • Special Value:如果操作不能马上进行,将会返回一个特殊的值,一般是true或者false;
  • Blocks:如果操作不能马上进行,操作会被阻塞;
  • TimesOut:如果操作不能马上进行,操作会被阻塞指定的时间,如果指定时间没执行,则返回一个特殊值,一般是true或者false。

下面来看由阻塞队列实现的生产者消费者模型,这里使用 take() 和 put() 方法,这里生产者和生产者,消费者和消费者之间不存在同步,所以会出现连续生成和连续消费的现象。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.com.codingce.juc.生产者消费者模型;

import java.util.concurrent.*;

/**
 * 使用 {@link BlockingQueue} 实现生产者消费者模型
 * <p>
 * 后端码匠
 *
 * @author mxz
 */
public class BlockingQueueExample {

    private static Integer count = 0;
    // 创建一个阻塞队列
    final BlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(10);

    public static void main(String[] args) throws InterruptedException {
        BlockingQueueExample example = new BlockingQueueExample();
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(example.new Producer());
        service.execute(example.new Producer());
        service.execute(example.new Consumer());
        service.shutdown();
        System.out.println(service.awaitTermination(15L, TimeUnit.SECONDS));
    }

    class Producer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000L);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                try {
                    blockingQueue.put(1);
                    count++;
                    System.out.println("*************** " + Thread.currentThread().getName() + ", 生产者生产, 目前总共有: " + count + " ***************");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class Consumer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                try {
                    blockingQueue.take();
                    count--;
                    System.out.println("--------------- " + Thread.currentThread().getName() + ", 消费者消费, 目前总共有: " + count + " ---------------");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

output

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 1 ---------------
*************** pool-1-thread-2, 生产者生产, 目前总共有: 1 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 2 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 2 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 1 ---------------
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 1 ---------------
*************** pool-1-thread-2, 生产者生产, 目前总共有: 3 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 2 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 5 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 5 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 4 ---------------
false
*************** pool-1-thread-1, 生产者生产, 目前总共有: 5 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 6 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 5 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 6 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 6 ---------------
*************** pool-1-thread-2, 生产者生产, 目前总共有: 6 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 7 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 7 ---------------
*************** pool-1-thread-2, 生产者生产, 目前总共有: 8 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 6 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 7 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 8 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 8 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 9 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 8 ---------------
*************** pool-1-thread-2, 生产者生产, 目前总共有: 10 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 9 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 10 ***************

0x24 信号量Semaphore

Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。Java中的Semaphore维护了一个许可集,一开始先设定这个许可集的数量,可以使用 acquire() 方法获得一个许可,当许可不足时会被阻塞,release() 添加一个许可。在下列代码中,还加入了另外一个 mutex 信号量,维护生产者消费者之间的同步关系,保证生产者和消费者之间的交替进行。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.com.codingce.juc.生产者消费者模型;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * {@link Semaphore} (信号量)
 * <p>
 * 后端码匠
 *
 * @author mxz
 */
public class SemaphoreExample {

    private static Integer count = 0;
    // 创建三个信号量
    final Semaphore notFull = new Semaphore(10);
    final Semaphore notEmpty = new Semaphore(0);
    final Semaphore mutex = new Semaphore(1);

    public static void main(String[] args) throws InterruptedException {
        SemaphoreExample example = new SemaphoreExample();
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(example.new Producer());
        service.execute(example.new Producer());
        service.execute(example.new Consumer());
        service.shutdown();
        System.out.println(service.awaitTermination(15L, TimeUnit.SECONDS));
    }

    class Producer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    notFull.acquire();
                    mutex.acquire();
                    count++;
                    System.out.println("*************** " + Thread.currentThread().getName() + ", 生产者生产, 目前总共有: " + count + " ***************");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    mutex.release();
                    notEmpty.release();
                }
            }
        }
    }

    class Consumer implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                try {
                    notEmpty.acquire();
                    mutex.acquire();
                    count--;
                    System.out.println("--------------- " + Thread.currentThread().getName() + ", 消费者消费, 目前总共有: " + count + " ---------------");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    mutex.release();
                    notFull.release();
                }
            }
        }
    }

}

output

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 2 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 1 ---------------
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 0 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 1 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 2 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 1 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 2 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 3 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 4 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 5 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 4 ---------------
false
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 3 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 4 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 5 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 6 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 5 ---------------
*************** pool-1-thread-1, 生产者生产, 目前总共有: 6 ***************
*************** pool-1-thread-2, 生产者生产, 目前总共有: 7 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 8 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 7 ---------------
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 6 ---------------
*************** pool-1-thread-2, 生产者生产, 目前总共有: 7 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 8 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 9 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 8 ---------------
*************** pool-1-thread-2, 生产者生产, 目前总共有: 9 ***************
*************** pool-1-thread-1, 生产者生产, 目前总共有: 10 ***************
--------------- pool-1-thread-3, 消费者消费, 目前总共有: 9 ---------------
*************** pool-1-thread-2, 生产者生产, 目前总共有: 10 ***************

0x3 拓展

0x31 管道输入输出流PipedInputStream和PipedOutputStream

Javaio包下,PipedOutputStreamPipedInputStream 分别是管道输出流管道输入流。 它们的作用是让多线程可以通过管道进行线程间的通讯。在使用管道通信时,必须将PipedOutputStream 和 PipedInputStream 配套使用使用方法:先创建一个管道输入流和管道输出流,然后将输入流和输出流进行连接,用生产者线程往管道输出流中写入数据,消费者在管道输入流中读取数据,这样就可以实现了不同线程间的相互通讯,但是这种方式在生产者和生产者、消费者和消费者之间不能保证同步,也就是说在一个生产者和一个消费者的情况下是可以生产者和消费者之间交替运行的多个生产者和多个消费者者之间则不行

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cn.com.codingce.juc.生产者消费者模型;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * {@link PipedInputStream} {@link PipedOutputStream}
 * <p>
 * 后端码匠
 *
 * @author mxz
 */
public class PipedInputStreamExample {

    final PipedInputStream pis = new PipedInputStream();
    final PipedOutputStream pos = new PipedOutputStream();

    {
        try {
            pis.connect(pos);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        PipedInputStreamExample example = new PipedInputStreamExample();
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(example.new Producer());
        service.execute(example.new Producer());
        service.execute(example.new Consumer());
        service.shutdown();
        System.out.println(service.awaitTermination(15L, TimeUnit.SECONDS));
    }

    class Producer implements Runnable {
        @Override
        public void run() {
            try {
                while (true) {
                    Thread.sleep(1000L);
                    int num = (int) (Math.random() * 10);
                    System.out.println("*************** " + Thread.currentThread().getName() + ", 生产者生产了一个数字, 该数字为: " + num + " ***************");
                    pos.write(num);
                    pos.flush();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    pos.close();
                    pis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class Consumer implements Runnable {
        @Override
        public void run() {
            try {
                while (true) {
                    Thread.sleep(1000L);
                    int num = pis.read();
                    System.out.println("--------------- " + Thread.currentThread().getName() + ", 消费者消费了一个数字, 该数字为: " + num + " ---------------");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    pos.close();
                    pis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

output

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 1 ***************
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 7 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 1 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 2 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 7 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 7 ---------------
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 2 ---------------
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 7 ***************
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 8 ***************
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 6 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 4 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 7 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 2 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 7 ---------------
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 3 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 0 ***************
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 1 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 8 ---------------
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 6 ---------------
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 1 ***************
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 7 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 9 ***************
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 1 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 4 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 7 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 2 ---------------
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 5 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 1 ***************
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 5 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 3 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 2 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 0 ---------------
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 5 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 8 ***************
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 0 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 1 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 1 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 8 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 1 ---------------
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 3 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 7 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 0 ***************
false
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 1 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 0 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 9 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 5 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 1 ---------------
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 7 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 7 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 7 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 4 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 7 ***************
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 5 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 5 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 2 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 1 ---------------
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 1 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 5 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 4 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 0 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 2 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 2 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 9 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 5 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 8 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 7 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 8 ---------------
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 2 ***************
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 2 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 5 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 0 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 3 ***************
*************** pool-1-thread-1, 生产者生产了一个数字, 该数字为: 7 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 1 ---------------
*************** pool-1-thread-2, 生产者生产了一个数字, 该数字为: 0 ***************
--------------- pool-1-thread-3, 消费者消费了一个数字, 该数字为: 8 ---------------
### 省略.......

项目地址:https://gitee.com/codingce/codingce-leetcode

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-01-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后端码匠 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
大神回归学界:何恺明宣布加入 MIT
「作为一位 FAIR 研究科学家,我将于 2024 年加入麻省理工学院(MIT)电气工程与计算机科学系 EECS 担任教职。」
机器之心
2023/08/08
4730
大神回归学界:何恺明宣布加入 MIT
何恺明被曝回归学界!面试MIT教职,大型DL追星现场来了
---- 新智元报道   编辑:桃子 【新智元导读】何恺明大神可能要回归学界了。MIT的一则公告称,何恺明将在下周一做学术演讲(Job Talks)。 大型Deep Learning追星现场要来了.... MIT CSAIL实验室发布了一则公告称,何恺明将在3月13日(下周一)到MIT做学术演讲。 乍一看,是学术演讲,其实这个研讨会是Job Talks(求职演讲)。 杜克大学陈怡然教授也称,一直听说何恺明在Market上,靴子终于落了地。 MIT被引用数,无人能敌 在MIT的演讲中,何恺明讲
新智元
2023/03/29
5470
何恺明被曝回归学界!面试MIT教职,大型DL追星现场来了
2023未来科学大奖公布,ResNet四位作者获数学与计算机科学奖
未来科学大奖设立于 2016 年,关注原创性的基础科学研究。目前设置了「生命科学奖」、「物质科学奖」和「数学与计算机科学奖」三大奖项,单项奖金 725 万元人民币(等值 100 万美元)。
机器之心
2023/09/08
5270
2023未来科学大奖公布,ResNet四位作者获数学与计算机科学奖
何恺明官宣加入MIT,正式回归学术界!
刚刚他正式宣布,自己将于2024年加入MIT EECS(电子工程和计算机科学系) 。
量子位
2023/08/05
2670
何恺明官宣加入MIT,正式回归学术界!
何恺明 MIT 最新演讲:未来工作将聚焦 AI for science
CV 人的大型追星现场来了。 作者 | 黄楠 编辑 | 陈彩娴 又一名 AI 大神有了新动向! 当地时间3月13日下午3点,何恺明在MIT做学术演讲。据现场网友所述,即便自己提前半小时去到现场,但仍挤不进会场,仅排队就拐了几个弯,MIT CSAIL 还临时开了隔壁会议室投屏,许多人是挤在小角落里听完全程的。 据 MIT CSAIL 实验室此前发布公告显示,本次何恺明的演讲主题是 "In Pursuit of Visual Intelligence"(追求视觉智能)。 在现场演讲中,何恺明按时间线顺序回顾其之
AI科技评论
2023/04/04
7850
何恺明 MIT 最新演讲:未来工作将聚焦 AI for science
90后首次现身!何恺明、孙剑团队斩获未来科学大奖,ResNet被引18万
值得一提的是,今年「数学与计算机科学奖」颁给了创世研究ResNet的团队,表彰他们人工智能做出了基础性贡献。
新智元
2023/09/09
4450
90后首次现身!何恺明、孙剑团队斩获未来科学大奖,ResNet被引18万
微软亚洲研究院20年20人
作为人工智能的“黄埔军校”,微软亚洲研究院(MSRA)这20年来,走出了无数传奇人物。
量子位
2018/12/07
1.3K0
何恺明!再斩ICCV 2017最佳论文
夏乙 若朴 发自 凹非寺 量子位 出品 | 公众号 QbitAI 何恺明第三次斩获顶会最佳论文! 昨天下午,ICCV 2017最佳论文公布。 何恺明为一作的Mask R-CNN论文,不负众望获得最佳论文(Marr Prize)。 另外,何恺明参与的另一篇论文:Focal Loss for Dense Object Detection,也被大会评为最佳学生论文。 作为计算机视觉领域的顶级会议,ICCV 2017共收到2143篇论文投稿,其中621篇被选为大会论文(入围比
量子位
2018/03/26
1.4K0
何恺明!再斩ICCV 2017最佳论文
旷视首席科学家、知名AI学者孙剑博士去世
机器之心报道 机器之心编辑部 如此优秀的学者逝世,实为 CV 领域一大痛事。 6 月 14 日,旷视科技发布讣告,旷视首席科学家、旷视研究院院长孙剑博士因突发疾病抢救无效,于 2022 年 6 月 14 日凌晨去世。 孙剑博士是人工智能领域的优秀学者。 孙剑博士本硕博期间均就读于西安交通大学,2003 年在西安交通大学获得博士学位,加入微软亚洲研究院,任至首席研究员。2015-2016 年在微软美国研究院任合伙人级研究主管。 在微软研究院工作了 13 年后,孙剑博士于 2016 年 7 月加入旷视科技,担
机器之心
2022/06/14
6930
旷视首席科学家、知名AI学者孙剑博士去世
旷视首席科学家、知名AI学者孙剑博士去世
关注并星标 从此不迷路 计算机视觉研究院 公众号ID|ComputerVisionGzq 学习群|扫码在主页获取加入方式 计算机视觉研究院专栏 作者:Edison_G 如此优秀的学者逝世,实为 CV 领域一大痛事。想想当年还被他问及残差网络原理及发展,可惜没有和AI领域界的优秀学者一起共事,祝一路走好! 转自《机器之心》 孙剑博士是人工智能领域的优秀学者。 孙剑博士本硕博期间均就读于西安交通大学,2003年在西安交通大学获得博士学位,加入微软亚洲研究院,任至首席研究员。2015-2016年在微软美国
计算机视觉研究院
2022/06/16
2320
旷视首席科学家、知名AI学者孙剑博士去世
“残差网络ResNet” 获得2023未来科学大奖!何恺明、张祥雨、任少卿、孙剑共享百万美元奖金
刚刚!2023年未来科学大奖名单公布,计算机视觉领域残差网络的四位作者:何恺明、张祥雨、任少卿、孙剑,共同获得数学与计算机科学奖。
大数据文摘
2023/09/06
4900
“残差网络ResNet” 获得2023未来科学大奖!何恺明、张祥雨、任少卿、孙剑共享百万美元奖金
大道至简,何恺明新论文火了:Masked Autoencoders让计算机视觉通向大模型
11 月 12 日,一篇由 Facebook AI 研究院完成、何恺明一作的论文《Masked Autoencoders Are Scalable Vision Learners》成为了计算机视觉圈的热门话题。
机器之心
2021/11/18
2K0
大道至简,何恺明新论文火了:Masked Autoencoders让计算机视觉通向大模型
哀悼!旷视首席科学家孙剑突然离世,终年45岁,曾任微软亚洲研究院首席研究员
点击图片立刻参与! 孙剑博士,一路走好。 作者 | 镁客星球编辑部 今天凌晨,巨星陨落。 6月14日,“AI四小龙”之一的旷视科技发布讣告,旷视首席科学家、旷视研究院院长孙剑博士因突发疾病抢救无效于2022年6月14日凌晨去世。 旷视科技在讣告中表示: 我们万分难过,旷视首席科学家、旷视研究院院长孙剑博士因突发疾病抢救无效,于2022年6月14日凌晨,永远离开了我们。 孙剑博士一生专注于科研工作。他的不幸离世,让旷视失去了一位在人工智能技术领域探索和创新的领路人。每一位和他共事过的旷视同学,失去了一位智
镁客网
2022/06/16
5000
哀悼!旷视首席科学家孙剑突然离世,终年45岁,曾任微软亚洲研究院首席研究员
何恺明的ResNet论文,被引量刚刚突破10万大关
「深度神经网络非常难以训练,我们提出的残差网络框架使得神经网络的训练变得容易很多。」文章摘要的开头如今已被无数研究者们细细读过。
机器之心
2021/12/22
1K0
何恺明的ResNet论文,被引量刚刚突破10万大关
何恺明时隔2年再发一作论文:为视觉大模型开路,“CVPR 2022最佳论文候选预定”
甚至在业内纷纷追求“大力出奇迹”、“暴力美学”的当下,何恺明还带着一种坚持独立思考的反共识气概。
量子位
2021/11/16
7450
悼念!AI大牛孙剑博士!
点击 机器学习算法与Python学习 ,选择加星标 精彩内容不迷路 量子位 | 公众号 QbitAI 旷视首席科学家、旷视研究院院长孙剑博士,今日凌晨因病不幸离世。 孙剑博士1976年10月出生,今年45岁。他曾任微软亚研院首席研究员,此前两次获CVPR最佳论文奖。 他最为人所熟知的成就,是带领何恺明等人做出的残差网络ResNet。ResNet在2015年提出之后,拿下过ImageNet冠军,并斩获了CVPR 2016最佳论文奖。 孙剑的博士研究生专业是模式识别与智能控制专业,作为微软亚洲研究院和西安交
昱良
2022/06/16
4240
悼念!AI大牛孙剑博士!
悼念!孙剑博士凌晨逝世,AI痛失大牛,旷视痛失技术领路人
编辑部 发自 凹非寺 量子位 | 公众号 QbitAI 旷视首席科学家、旷视研究院院长孙剑博士,今日凌晨因病不幸离世。 孙剑博士1976年10月出生,今年45岁。他曾任微软亚研院首席研究员,此前两次获CVPR最佳论文奖。 他最为人所熟知的成就,是带领何恺明等人做出的残差网络ResNet。ResNet在2015年提出之后,拿下过ImageNet冠军,并斩获了CVPR 2016最佳论文奖。 孙剑的博士研究生专业是模式识别与智能控制专业,作为微软亚洲研究院和西安交通大学联合培养的研究生,他曾师从沈向洋博士。 沈
量子位
2022/06/14
2090
悼念!孙剑博士凌晨逝世,AI痛失大牛,旷视痛失技术领路人
2018年度 「微软学者」获奖名单公布!11 名计算机界新力军崭露头角
AI 科技评论按:「微软学者」奖学金是微软亚洲研究院 1999 年启动的一项面向亚太地区计算机科学以及相关专业的优秀博士生的项目。该奖学金项目旨在发掘、支持和鼓励优秀的、有潜力的低年级博士生更好地开展研究工作。
AI科技评论
2018/12/07
1.2K0
【ICCV2017视觉盛宴概况】何恺明博士包揽最佳论文和最佳学生论文奖!Facebook成大赢家!
【导读】当地时间 10月 22 日到10月29日,两年一度的计算机视觉国际顶级会议 International Conference on Computer Vision(ICCV 2017)正在意大利威尼斯开幕,来自世界各地的计算机视觉专家聚集在威尼斯介绍计算机视觉和相关领域的最新进展。大会公布了各奖项包括最佳论文奖(Marr Prize)、最佳学生论文奖、Honorable mentions、Azriel Rosenfeld lifetime achievement award、Distinguishe
WZEARW
2018/04/09
1.2K0
【ICCV2017视觉盛宴概况】何恺明博士包揽最佳论文和最佳学生论文奖!Facebook成大赢家!
CVPR 2022缅怀孙剑!同济、阿里获最佳学生论文奖,何恺明入围
---- 新智元报道   编辑:编辑部 【新智元导读】2年没见,CVPR 2022终于来线下了,6000人参会火爆。最佳论文花落苏黎世理工,同济、阿里摘最佳学生论文桂冠。斯坦福大学教授李飞飞荣获「黄煦涛纪念奖」。此外,大会现场还播放了一段视频,缅怀孙剑博士。 6月21日,CVPR 2022正式拉开帷幕。 受疫情影响开了两年的虚拟会议之后,本届大会终于恢复了线下出席的方式。 于是,线下注册参会的人数一下子就达到了5641人,比2017年还多。 从现场发来的图片看,真可谓是人山人海。 CVPR 2022
新智元
2022/06/24
8780
CVPR 2022缅怀孙剑!同济、阿里获最佳学生论文奖,何恺明入围
推荐阅读
大神回归学界:何恺明宣布加入 MIT
4730
何恺明被曝回归学界!面试MIT教职,大型DL追星现场来了
5470
2023未来科学大奖公布,ResNet四位作者获数学与计算机科学奖
5270
何恺明官宣加入MIT,正式回归学术界!
2670
何恺明 MIT 最新演讲:未来工作将聚焦 AI for science
7850
90后首次现身!何恺明、孙剑团队斩获未来科学大奖,ResNet被引18万
4450
微软亚洲研究院20年20人
1.3K0
何恺明!再斩ICCV 2017最佳论文
1.4K0
旷视首席科学家、知名AI学者孙剑博士去世
6930
旷视首席科学家、知名AI学者孙剑博士去世
2320
“残差网络ResNet” 获得2023未来科学大奖!何恺明、张祥雨、任少卿、孙剑共享百万美元奖金
4900
大道至简,何恺明新论文火了:Masked Autoencoders让计算机视觉通向大模型
2K0
哀悼!旷视首席科学家孙剑突然离世,终年45岁,曾任微软亚洲研究院首席研究员
5000
何恺明的ResNet论文,被引量刚刚突破10万大关
1K0
何恺明时隔2年再发一作论文:为视觉大模型开路,“CVPR 2022最佳论文候选预定”
7450
悼念!AI大牛孙剑博士!
4240
悼念!孙剑博士凌晨逝世,AI痛失大牛,旷视痛失技术领路人
2090
2018年度 「微软学者」获奖名单公布!11 名计算机界新力军崭露头角
1.2K0
【ICCV2017视觉盛宴概况】何恺明博士包揽最佳论文和最佳学生论文奖!Facebook成大赢家!
1.2K0
CVPR 2022缅怀孙剑!同济、阿里获最佳学生论文奖,何恺明入围
8780
相关推荐
大神回归学界:何恺明宣布加入 MIT
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验