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

Java 21中如何基于用户输入暂停与恢复虚拟线程?

Java 21虚拟线程实现暂停/恢复串口任务方案

针对Java 21虚拟线程的暂停恢复需求,不需要依赖未公开的continuation API,用JDK标准同步工具即可实现轻量、可靠的控制,以下是两种实用方案:

方案一:基于LockSupport的轻量实现

LockSupport.park()/unpark()是虚拟线程友好的阻塞方式,挂起时不会占用平台线程资源,适合简单的暂停恢复场景。

可暂停的串口任务类

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
import jssc.SerialPort;
import jssc.SerialPortException;

public class SerialPortTask implements Runnable {
    private final SerialPort serialPort;
    private final AtomicBoolean paused = new AtomicBoolean(false);
    private volatile boolean running = true;
    private volatile Thread currentVirtualThread;

    public SerialPortTask(String portName) throws SerialPortException {
        this.serialPort = new SerialPort(portName);
        serialPort.openPort();
        // 配置串口参数(根据实际需求调整)
        serialPort.setParams(SerialPort.BAUDRATE_9600,
                             SerialPort.DATABITS_8,
                             SerialPort.STOPBITS_1,
                             SerialPort.PARITY_NONE);
    }

    @Override
    public void run() {
        currentVirtualThread = Thread.currentThread();
        try {
            while (running) {
                // 检查暂停状态,若已暂停则挂起线程
                checkPause();

                // 执行串口核心逻辑:读取/发送数据
                if (serialPort.isOpened()) {
                    byte[] receivedData = serialPort.readBytes();
                    if (receivedData != null) {
                        processReceivedData(receivedData);
                    }
                }

                // 避免循环过于密集,可根据需求调整延迟
                Thread.sleep(100);
            }
        } catch (SerialPortException | InterruptedException e) {
            // 按需处理异常,比如日志记录
            e.printStackTrace();
        } finally {
            // 关闭串口资源
            try {
                if (serialPort.isOpened()) {
                    serialPort.closePort();
                }
            } catch (SerialPortException e) {
                e.printStackTrace();
            }
        }
    }

    private void checkPause() {
        // 用while循环处理虚假唤醒,确保只有暂停状态解除后才继续执行
        while (paused.get()) {
            LockSupport.park(this);
        }
    }

    // 外部调用暂停任务
    public void pauseTask() {
        paused.set(true);
    }

    // 外部调用恢复任务
    public void resumeTask() {
        paused.set(false);
        // 唤醒挂起的虚拟线程
        LockSupport.unpark(currentVirtualThread);
    }

    // 停止任务(需唤醒线程避免永久挂起)
    public void stopTask() {
        running = false;
        resumeTask();
    }

    // 自定义数据处理逻辑
    private void processReceivedData(byte[] data) {
        System.out.println("收到串口数据:" + new String(data));
    }
}

UI层控制示例(以Swing为例)

import javax.swing.*;
import java.awt.*;
import jssc.SerialPortException;

public class SerialPortControllerUI extends JFrame {
    private SerialPortTask serialTask;
    private Thread virtualThread;

    public SerialPortControllerUI() {
        setTitle("串口任务控制器");
        setSize(350, 150);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new FlowLayout(FlowLayout.CENTER, 10, 20));

        JButton startBtn = new JButton("启动任务");
        JButton pauseBtn = new JButton("暂停");
        JButton resumeBtn = new JButton("恢复");
        JButton stopBtn = new JButton("停止任务");

        startBtn.addActionListener(e -> {
            try {
                // 替换为实际串口名称
                serialTask = new SerialPortTask("COM3");
                // 创建并启动虚拟线程
                virtualThread = Thread.ofVirtual().start(serialTask);
            } catch (SerialPortException ex) {
                JOptionPane.showMessageDialog(this, "串口打开失败:" + ex.getMessage());
            }
        });

        pauseBtn.addActionListener(e -> {
            if (serialTask != null) {
                serialTask.pauseTask();
            }
        });

        resumeBtn.addActionListener(e -> {
            if (serialTask != null) {
                serialTask.resumeTask();
            }
        });

        stopBtn.addActionListener(e -> {
            if (serialTask != null) {
                serialTask.stopTask();
                try {
                    virtualThread.join();
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        add(startBtn);
        add(pauseBtn);
        add(resumeBtn);
        add(stopBtn);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new SerialPortControllerUI().setVisible(true));
    }
}

方案二:基于Condition的灵活实现

如果需要更复杂的同步逻辑(比如多个条件等待),可以用ReentrantLock搭配Condition实现,同样兼容虚拟线程。

核心任务类示例

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import jssc.SerialPort;
import jssc.SerialPortException;

public class ConditionBasedSerialTask implements Runnable {
    private final SerialPort serialPort;
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition pausedCondition = lock.newCondition();
    private volatile boolean paused = false;
    private volatile boolean running = true;

    public ConditionBasedSerialTask(String portName) throws SerialPortException {
        this.serialPort = new SerialPort(portName);
        serialPort.openPort();
        serialPort.setParams(SerialPort.BAUDRATE_9600,
                             SerialPort.DATABITS_8,
                             SerialPort.STOPBITS_1,
                             SerialPort.PARITY_NONE);
    }

    @Override
    public void run() {
        try {
            while (running) {
                lock.lock();
                try {
                    // 等待暂停状态解除
                    while (paused) {
                        pausedCondition.await();
                    }
                } finally {
                    lock.unlock();
                }

                // 执行串口操作
                if (serialPort.isOpened()) {
                    byte[] data = serialPort.readBytes();
                    if (data != null) {
                        processData(data);
                    }
                }

                Thread.sleep(100);
            }
        } catch (SerialPortException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            try {
                if (serialPort.isOpened()) {
                    serialPort.closePort();
                }
            } catch (SerialPortException e) {
                e.printStackTrace();
            }
        }
    }

    public void pause() {
        lock.lock();
        try {
            paused = true;
        } finally {
            lock.unlock();
        }
    }

    public void resume() {
        lock.lock();
        try {
            paused = false;
            pausedCondition.signal();
        } finally {
            lock.unlock();
        }
    }

    public void stop() {
        running = false;
        resume();
    }

    private void processData(byte[] data) {
        System.out.println("收到串口数据:" + new String(data));
    }
}

关键注意事项

  1. 检查点位置:必须在任务的循环逻辑中插入暂停检查,确保暂停请求能被及时响应,避免在长时间阻塞的操作(比如未设置超时的串口读取)中无法暂停。
  2. 虚假唤醒处理:用while循环而非if判断暂停状态,防止线程被意外唤醒后错误继续执行。
  3. 资源清理:停止任务时必须调用恢复方法,避免虚拟线程永久挂起无法退出,同时要确保串口资源被正确关闭。
  4. 避免使用未公开API:continuation是JDK内部API,无兼容性保证,生产环境禁止使用,标准同步工具完全能满足需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 07:52:02