You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Java线程实现并发执行?

问题根源与解决方案

看起来你是把生产者和消费者的逻辑放在同一个线程里顺序执行了!不管你在Create方法里加多少sleep,只要是单线程顺序调用,就一定会等Create完全执行完,才会轮到Consume启动——这根本不是并发执行,自然做不到一边生产一边消费的效果。

要实现生产者-消费者模式,核心是把生产和消费逻辑放到独立的线程中运行,同时用线程安全的共享容器来传递对象,避免并发操作导致的数据问题。下面给你具体的实现思路和代码示例:

核心解决步骤

  • 用线程安全的队列替代自定义堆:推荐java.util.concurrent.LinkedBlockingQueue,它自带阻塞等待机制,不用自己写轮询或同步逻辑。
  • 将生产、消费逻辑封装为Runnable:让它们能在独立线程中运行。
  • 启动独立线程分别执行生产和消费逻辑,实现并发运行。

完整示例代码

import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;

// 假设这是你要生产/消费的对象类型
class MyTask {
    private int id;
    public MyTask(int id) { this.id = id; }
    public int getId() { return id; }
}

// 生产者逻辑:往队列中添加对象
class Producer implements Runnable {
    private final LinkedBlockingQueue<MyTask> sharedQueue;
    private final int totalTasks;

    public Producer(LinkedBlockingQueue<MyTask> queue, int totalTasks) {
        this.sharedQueue = queue;
        this.totalTasks = totalTasks;
    }

    @Override
    public void run() {
        Random random = new Random();
        try {
            for (int i = 0; i < totalTasks; i++) {
                // 模拟生产耗时(比如创建对象的时间)
                Thread.sleep(random.nextInt(1000));
                MyTask newTask = new MyTask(i);
                sharedQueue.put(newTask); // 队列满时自动阻塞等待
                System.out.println("生产任务: ID=" + newTask.getId());
            }
        } catch (InterruptedException e) {
            // 优雅处理线程中断
            Thread.currentThread().interrupt();
            System.out.println("生产者线程被中断");
        }
    }
}

// 消费者逻辑:从队列中移除对象
class Consumer implements Runnable {
    private final LinkedBlockingQueue<MyTask> sharedQueue;

    public Consumer(LinkedBlockingQueue<MyTask> queue) {
        this.sharedQueue = queue;
    }

    @Override
    public void run() {
        Random random = new Random();
        try {
            while (!Thread.currentThread().isInterrupted()) {
                MyTask task = sharedQueue.take(); // 队列空时自动阻塞等待
                // 模拟消费耗时(比如处理对象的时间)
                Thread.sleep(random.nextInt(1000));
                System.out.println("消费任务: ID=" + task.getId());
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.println("消费者线程被中断");
        }
    }
}

public class JavaApplication2 {
    public static void main(String[] args) throws InterruptedException {
        // 初始化线程安全的共享队列
        LinkedBlockingQueue<MyTask> taskQueue = new LinkedBlockingQueue<>();
        // 设定生产者要生产的总任务数
        int totalProduction = 5;

        // 创建并启动生产者线程
        Thread producerThread = new Thread(new Producer(taskQueue, totalProduction));
        // 创建并启动消费者线程
        Thread consumerThread = new Thread(new Consumer(taskQueue));

        producerThread.start();
        consumerThread.start();

        // 等待生产者完成所有生产任务
        producerThread.join();
        // 给消费者留时间处理剩余任务,然后优雅中断它
        Thread.sleep(1500);
        consumerThread.interrupt();
        consumerThread.join();

        System.out.println("所有生产消费任务完成");
    }
}

关键细节说明

  1. 线程安全的队列:LinkedBlockingQueue的put()和take()方法是线程安全的,并且自带阻塞机制——当队列满时,生产者会自动等待;当队列空时,消费者会自动等待,不用你手动写同步锁或轮询逻辑。
  2. 独立线程运行:生产者和消费者在各自的线程中执行,所以它们的操作是并发的,你会看到控制台中生产和消费的日志交替输出,实现了你要的"一边添加一边移除"的效果。
  3. 优雅停止线程:用interrupt()中断线程,而不是强制杀死,这样能保证线程有机会清理资源,避免内存泄漏。

额外注意点

  • 如果你坚持要用自己实现的"堆",一定要给它加上线程安全的同步措施(比如用synchronized块,或者用ReentrantLock),否则并发操作会出现数据丢失、重复消费等问题。但更推荐直接用JUC包下的线程安全集合,效率和可靠性都更高。
  • 如果需要多个生产者或多个消费者,只需要多创建几个对应的线程并启动即可,队列会自动协调它们的操作。

内容的提问来源于stack exchange,提问作者Some_Dude

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:42:30