在java中如何从Executors.newFixedThreadPool(MAX_THREAD_COUNT())迁移到虚拟线程

Tug*_*cak 5 java executorservice virtual-threads

动机:尝试迁移虚拟线程。

问题:尽管虚拟线程很便宜,但操作系统可能会发现同时堆叠某些进程很可疑,例如在网络上搜索 IP 或端口。

我使用下面的代码来限制线程的创建。TS_NetworkIPUtils TS_NetworkPortUtils

var executor = useVirtualThread
                    ? Executors.newVirtualThreadPerTaskExecutor()
                    : Executors.newFixedThreadPool(MAX_THREAD_COUNT());
Run Code Online (Sandbox Code Playgroud)

是否可以创建一个执行器服务来创建虚拟线程并同时具有限制功能?

Bas*_*que 1

太长了;博士

\n
\n

是否可以创建一个执行器服务来创建虚拟线程并同时具有限制功能?

\n
\n

是的。

\n

堆积许多虚拟线程,在等待任何有限数量的当前正在执行的任务释放计数信号量时被阻塞。

\n

细节

\n
\n

我使用下面的代码来限制线程的创建。TS_NetworkIPUtils

\n
\n

不,不限制线程数。虚拟线程的设计极其\xe2\x80\x9ccheap\xe2\x80\x9d,默认情况下占用很少的系统资源(内存、CPU)。您可能可以一次支持数百万个虚拟线程。

\n

当您的任务成本很高时,您可能需要限制并发任务的数量。继续堆叠许多线程,但阻止它们的执行以等待一定数量的并发任务忙于执行。阻塞虚拟线程的成本非常低(它们的存在原因\xc2\xa0d\xe2\x80\x99\xc3\xaatre),所以如果它们堆积起来也没有问题。

\n

使用计数信号量来限制同时执行的任务

\n

您可以使用计数信号量来限制虚拟线程中同时运行的任务数量。请参阅Cay Horstmann 的教程虚拟线程中的速率限制部分。

\n

就像下面的例子一样。我们提交 15 个任务,但同时执行的任务仅限 5 个或更少。它new Semaphore ( 5 )提供了五个可以获取和释放的许可证。这些许可证就像从图书馆借了一本书总共五本,最终归还给其他人借阅\xe2\x80\x94\xc2\xa0很多借阅者,但一次只能借五本。

\n

请注意后面的任务如何等待几秒钟以获得我们的计数信号量的许可。

\n

最后,在完成所有提交的任务后,我们退出 try-with-resources 语法块。

\n

(警告:我只是快速编写了这个代码示例,没有经过太多思考。我正在寻找比链接的 Cay Horstmann 教程中看到的示例更简单的东西。)

\n
package work.basil.example.threading;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.SequencedCollection;\nimport java.util.concurrent.*;\nimport java.util.concurrent.locks.LockSupport;\n\npublic class LimitTasks\n{\n    public static void main ( String[] args )\n    {\n        LimitTasks app = new LimitTasks ( );\n        app.demo ( );\n    }\n\n    private void demo ( )\n    {\n        System.out.println ( "Demo start. " + Instant.now ( ) );\n\n        SequencedCollection < String > log = new CopyOnWriteArrayList <> ( );  // System.out.println calls across threads do *NOT* necessarily appear on console in chronological order.\n        final Semaphore TASKS_PERMITS = new Semaphore ( 5 );\n        log.add ( "Permits available: " + TASKS_PERMITS.availablePermits ( ) );\n        try (\n                ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor ( ) ;\n        )\n        {\n            for ( int nthTask = 1 ; nthTask <= 15 ; nthTask++ )\n            {\n                executorService.submit ( new PrintIt ( nthTask , TASKS_PERMITS , log ) );\n            }\n        }\n        log.add ( "After try-with-resources on ExecutorService. " + Instant.now ( ) );\n        log.forEach ( System.out :: println );\n        System.out.println ( "Demo done. " + Instant.now ( ) );\n    }\n}\n\nclass PrintIt implements Runnable\n{\n    private final int label;\n    private final Semaphore tasksPermits;\n    private final SequencedCollection < String > log;\n\n    public PrintIt ( final int label , final Semaphore tasksPermits , final SequencedCollection < String > log )\n    {\n        this.label = label;\n        this.tasksPermits = tasksPermits;\n        this.log = log;\n    }\n\n    @Override\n    public void run ( )\n    {\n        this.log.add ( "nthTask " + label + ". Approximately " + this.tasksPermits.getQueueLength ( ) + " tasks waiting for a permit. " + Instant.now ( ) );\n        long startNanos = System.nanoTime ( );\n        try\n        {\n            this.tasksPermits.acquire ( );\n            long elapsed = System.nanoTime ( ) - startNanos ;\n            this.log.add ( "nthTask " + label + " waited " + Duration.ofNanos ( elapsed ) + " for a permit. Permits available: " + this.tasksPermits.availablePermits ( ) + ". " + Instant.now ( ) );\n            long low = Duration.ofSeconds ( 2 ).toNanos ( );\n            long high = Duration.ofSeconds ( 10 ).toNanos ( );\n            long random = ThreadLocalRandom.current ( ).nextLong ( low , high );\n            LockSupport.parkNanos ( random );\n            this.log.add ( "nthTask " + label + " running at " + Instant.now ( ) + ". Permits available: " + this.tasksPermits.availablePermits ( ) + "." );\n        } catch ( InterruptedException e )\n        {\n            throw new RuntimeException ( e );\n        } finally\n        {\n            this.tasksPermits.release ( );\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

当在配备 IntelliJ IDEA 2023.3.3(终极版)Apple Silicon 的 Mac 上的 Java 21 上运行时。

\n
Demo start. 2024-02-06T04:42:12.414617Z\nPermits available: 5\nnthTask 3. Approximately 0 tasks waiting for a permit. 2024-02-06T04:42:12.425896Z\nnthTask 4. Approximately 0 tasks waiting for a permit. 2024-02-06T04:42:12.425813Z\nnthTask 7. Approximately 0 tasks waiting for a permit. 2024-02-06T04:42:12.427279Z\nnthTask 1. Approximately 0 tasks waiting for a permit. 2024-02-06T04:42:12.425813Z\nnthTask 2. Approximately 0 tasks waiting for a permit. 2024-02-06T04:42:12.425813Z\nnthTask 9. Approximately 0 tasks waiting for a permit. 2024-02-06T04:42:12.428066Z\nnthTask 10. Approximately 0 tasks waiting for a permit. 2024-02-06T04:42:12.428092Z\nnthTask 8. Approximately 0 tasks waiting for a permit. 2024-02-06T04:42:12.427894Z\nnthTask 5. Approximately 0 tasks waiting for a permit. 2024-02-06T04:42:12.425983Z\nnthTask 6. Approximately 0 tasks waiting for a permit. 2024-02-06T04:42:12.426432Z\nnthTask 11. Approximately 5 tasks waiting for a permit. 2024-02-06T04:42:12.435172Z\nnthTask 12. Approximately 5 tasks waiting for a permit. 2024-02-06T04:42:12.435178Z\nnthTask 13. Approximately 7 tasks waiting for a permit. 2024-02-06T04:42:12.435214Z\nnthTask 14. Approximately 7 tasks waiting for a permit. 2024-02-06T04:42:12.435225Z\nnthTask 15. Approximately 9 tasks waiting for a permit. 2024-02-06T04:42:12.435261Z\nnthTask 3 waited PT0.0088205S for a permit. Permits available: 0. 2024-02-06T04:42:12.434720Z\nnthTask 2 waited PT0.008820167S for a permit. Permits available: 1. 2024-02-06T04:42:12.434640Z\nnthTask 4 waited PT0.008743834S for a permit. Permits available: 1. 2024-02-06T04:42:12.434705Z\nnthTask 7 waited PT0.007267583S for a permit. Permits available: 1. 2024-02-06T04:42:12.434666Z\nnthTask 1 waited PT0.008801666S for a permit. Permits available: 2. 2024-02-06T04:42:12.434619Z\nnthTask 2 running at 2024-02-06T04:42:15.306355Z. Permits available: 0.\nnthTask 9 waited PT2.887408834S for a permit. Permits available: 0. 2024-02-06T04:42:15.315471Z\nnthTask 3 running at 2024-02-06T04:42:17.420189Z. Permits available: 0.\nnthTask 10 waited PT4.9929405S for a permit. Permits available: 0. 2024-02-06T04:42:17.421040Z\nnthTask 7 running at 2024-02-06T04:42:17.920249Z. Permits available: 0.\nnthTask 8 waited PT5.493109666S for a permit. Permits available: 0. 2024-02-06T04:42:17.921006Z\nnthTask 4 running at 2024-02-06T04:42:18.204203Z. Permits available: 0.\nnthTask 5 waited PT5.779108792S for a permit. Permits available: 0. 2024-02-06T04:42:18.205082Z\nnthTask 9 running at 2024-02-06T04:42:19.479390Z. Permits available: 0.\nnthTask 6 waited PT7.053674S for a permit. Permits available: 0. 2024-02-06T04:42:19.480079Z\nnthTask 1 running at 2024-02-06T04:42:19.800778Z. Permits available: 0.\nnthTask 11 waited PT7.366630625S for a permit. Permits available: 0. 2024-02-06T04:42:19.801791Z\nnthTask 10 running at 2024-02-06T04:42:20.015210Z. Permits available: 0.\nnthTask 12 waited PT7.580567167S for a permit. Permits available: 0. 2024-02-06T04:42:20.015699Z\nnthTask 11 running at 2024-02-06T04:42:24.640389Z. Permits available: 0.\nnthTask 13 waited PT12.205975708S for a permit. Permits available: 0. 2024-02-06T04:42:24.641142Z\nnthTask 8 running at 2024-02-06T04:42:26.301821Z. Permits available: 0.\nnthTask 14 waited PT13.867504542S for a permit. Permits available: 0. 2024-02-06T04:42:26.302663Z\nnthTask 12 running at 2024-02-06T04:42:26.407675Z. Permits available: 0.\nnthTask 15 waited PT13.972995459S for a permit. Permits available: 0. 2024-02-06T04:42:26.408182Z\nnthTask 5 running at 2024-02-06T04:42:27.728516Z. Permits available: 0.\nnthTask 6 running at 2024-02-06T04:42:28.044373Z. Permits available: 1.\nnthTask 15 running at 2024-02-06T04:42:29.974056Z. Permits available: 2.\nnthTask 13 running at 2024-02-06T04:42:30.613859Z. Permits available: 3.\nnthTask 14 running at 2024-02-06T04:42:33.088984Z. Permits available: 4.\nAfter try-with-resources on ExecutorService. 2024-02-06T04:42:33.089508Z\nDemo done. 2024-02-06T04:42:33.094512Z\n\nProcess finished with exit code 0\n
Run Code Online (Sandbox Code Playgroud)\n
\n

有关虚拟线程的更多信息,请观看 Ron Pressler、Alan Bateman 或 Jos\xc3\xa9 Paumard 精彩的视频演讲。并阅读JEP 444

\n