Java中有没有办法暂停和恢复虚拟线程?

问题描述 投票:0回答:1

我正在开发一个Java程序,它使用虚拟线程来执行特定任务(与jssc的串行通信程序)。我想知道是否有办法根据用户输入暂停和恢复这些虚拟线程。我读过一些关于“继续”的内容,但它似乎还无法使用。

例如,我希望当用户在程序界面上按下“暂停”按钮时暂停程序,并在用户单击“播放”按钮时恢复程序。

我正在使用 Java 21,目前没有使用任何特定的库或框架进行线程管理。

提前谢谢您!

java pause resume jssc virtual-threads
1个回答
0
投票

是的,锁和信号量的工作原理是一样的

虚拟线程在锁和信号量方面的行为相同。因此,您可以对虚拟线程使用与平台线程相同的方法。

引用JEP 444

支持锁定的原始 API java.util.concurrent.LockSupport 现在支持虚拟线程……使所有使用它的 API(锁、信号量、阻塞队列等)在虚拟线程中调用时能够优雅地停放。

更好:放弃而不是暂停

但是,您可能会错过虚拟线程的好处。

他们发明的原因是提供廉价线程,这意味着对内存、CPU、JVM 或主机操作系统的影响很小。虚拟线程就像面巾纸需要时,拿一张新的、使用并丢弃。因此,与其暂停和恢复虚拟线程,不如考虑仅处理当前虚拟线程,然后在需要时启动另一个虚拟线程。

示例应用程序

这里是一个示例应用程序,它就是这样做的。启动后,该应用程序每秒发出一次蜂鸣声。在控制台上,用户可以暂停蜂鸣声,并恢复蜂鸣声。或者用户这么认为。暂停确实让当前发出声音的虚拟线程结束运行并死亡。恢复实际上启动了一个新的虚拟线程,以每秒蜂鸣声重新开始。

在现代 Java 中,我们很少需要直接处理

Thread
类。通常最好让执行程序服务来处理线程。这里我们选择使用由虚拟线程支持的执行器服务。

请注意,执行者服务是

AutoCloseable
。这意味着我们可以使用 try-with-resources 语法来自动结束执行器服务。

我们在这里使用线程安全的集合来充当日志,在应用程序执行期间收集反馈。这是完成的,而不是直接调用

System.out.println
,因为这些调用的输出在跨线程时不一定按时间顺序出现在控制台上。 package work.basil.example.threading; import java.time.Duration; import java.time.Instant; import java.util.Scanner; import java.util.SequencedCollection; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicReference; public class Pausing { static final SequencedCollection < String > log = new CopyOnWriteArrayList <>( ); public static void main ( String[] args ) { Pausing app = new Pausing( ); app.demo( ); } private void demo ( ) { log.add( "INFO - starting `demo` method at " + Instant.now( ) + " in thread id: " + Thread.currentThread( ).threadId( ) + " thread name: " + Thread.currentThread( ).getName( ) ); final AtomicReference < BeepingCondition > beepingStatus = new AtomicReference <>( BeepingCondition.BEEPING ); try ( ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor( ) ; ) { Future < ? > beepingFuture = executorService.submit( new Beeper( beepingStatus ) ); Scanner scanner = new Scanner( System.in ); System.out.println( "Beeper demo has commenced. Hear a beep every second." ); while ( beepingStatus.get( ) != BeepingCondition.ENDED ) { System.out.println( "To pause the beeping, type 'pause'. To restart beeping, 'beep'. To end this program, 'stop'. " ); String input = scanner.nextLine( ).toLowerCase( ); // Blocks here until a line sent by user. log.add( "INFO - User intered input into `demo` method at " + Instant.now( ) + " in thread id: " + Thread.currentThread( ).threadId( ) + " thread name: " + Thread.currentThread( ).getName( ) + " Input: " + input ); switch ( input ) { case "beep" -> { if ( beepingStatus.get( ) == BeepingCondition.BEEPING ) { // Do nothing. Already beeping. } else // Else not currently beeping. Start beeping again. { beepingFuture = executorService.submit( new Beeper( beepingStatus ) ); beepingStatus.set( BeepingCondition.BEEPING ); } } case "pause" -> { if ( beepingStatus.get( ) == BeepingCondition.PAUSED ) { // Do nothing. Already paused. } else // Else not currently beeping. Start beeping again. { beepingFuture.cancel( true ); beepingStatus.set( BeepingCondition.PAUSED ); } } case "stop" -> { beepingFuture.cancel( true ); beepingStatus.set( BeepingCondition.ENDED ); } default -> { System.out.println( "Your input is unexpected. Try again. " ); } } } } log.add( "INFO - ending `demo` method at " + Instant.now( ) + " in thread id: " + Thread.currentThread( ).threadId( ) + " thread name: " + Thread.currentThread( ).getName( ) ); log.forEach( System.out :: println ); } static class Beeper implements Runnable { private final AtomicReference < BeepingCondition > keepOnBeeping; public Beeper ( final AtomicReference < BeepingCondition > continueBeeping ) { this.keepOnBeeping = continueBeeping; } @Override public void run ( ) { log.add( "INFO - starting `run` method at " + Instant.now( ) + " in thread id: " + Thread.currentThread( ).threadId( ) + " thread name: " + Thread.currentThread( ).getName( ) ); while ( this.keepOnBeeping.get( ) != BeepingCondition.ENDED ) { java.awt.Toolkit.getDefaultToolkit( ).beep( ); try { Thread.sleep( Duration.ofSeconds( 1 ) ); } catch ( InterruptedException e ) { log.add( "INFO - `run` method interrupted at " + Instant.now( ) + " in thread id: " + Thread.currentThread( ).threadId( ) + " thread name: " + Thread.currentThread( ).getName( ) ); break; // Bail out of this `while` loop. } } log.add( "INFO - ending `run` method at " + Instant.now( ) + " in thread id: " + Thread.currentThread( ).threadId( ) + " thread name: " + Thread.currentThread( ).getName( ) ); } } enum BeepingCondition { BEEPING, PAUSED, ENDED } }

© www.soinside.com 2019 - 2024. All rights reserved.