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

