结构化并发 (Java & Kotlin)

本文介绍了结构化并发的概念,如何解决传统并发编程中的线程泄露和取消延迟问题,以及在Java(StructuredTaskScope)和Kotlin(协程)中的实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 概念

        官方解释:结构化并发将不同线程中运行的相关任务视为单个工作单元,从而简化错误处理和取消,提高了可靠性,并增强了可观察性。

        个人理解:结构化并发是一种编程风格,目的是简化并发编程降低出错风险。官方把这种风格标准化为一个模版放进了自己的API中。

1. 传统并发弊端

        在传统的java并发编程中,线程之间并不存在从属关系,当业务分布在不同的线程中,线程又相互嵌套或等待时,这会使得管理各线程生命周期的难度加大,稍有不慎就会造成线程泄露和取消延迟的风险。

private static void threadTest(){
    System.out.println("--start--");

    var thread1 = Thread.ofPlatform().start(()->{
        var thread2 = Thread.ofPlatform().start(()->{
            for(int i=0;i<10;i++){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread2: " + i);
            }
            System.out.println("thread2: END");
        });
        for(int i=0;i<10;i++){
            if(!Thread.currentThread().isInterrupted()){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                System.out.println("thread1: " + i);
            }
        }
        System.out.println("thread1: END");
    });

    try {
        Thread.sleep(500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    thread1.interrupt();

    System.out.println("--end--");
}

--start--
thread2: 0
thread1: 0
thread1: 1
thread2: 1
thread1: 2
thread2: 2
thread2: 3
thread1: 3
--end--
thread1: 4
thread1: END
thread2: 4
thread2: 5
thread2: 6
thread2: 7
thread2: 8
thread2: 9
thread2: END

        上述例子是在线程thread1中创建并启动了线程thread2,当两个线程都还处于活动状态时中断了线程thread1。根据运行结果可以看出即使thread1停止后,thread2并没有停止。这样会导致线程泄露。并且可以看出线程thread1被中断后任然输出了一些内容后才停止的,这样的中断不及时会导致一些不可预料的错误。

2. 结构化并发优势

        从上述实例可以得出我们最至少需要解决的两个问题:一是线程泄露,需要让子线程和父线程有联级关系;二是取消延迟,不能以标志位的形式判断状态;

        结构化并发就是为了提倡一种可以消除取消和关闭带来的常见风险的并发编程风格,并提高并发代码的可观察性。

二 实现方案

1. StructuredTaskScope --Java

        在原本的JDK中并不存在结构化并行的接口,用户可以通过使用众多的线程框架或者搭建自己的线程模版来达到结构化并行的目的。但实际上早在JDK19之前就已经在孵化,并在更新的JDK21中正式出现。

private static void threadTest() {

    System.out.println("--start--");
    try(var scope = new StructuredTaskScope<Object>()){
        scope.fork(()->{
            scope.fork(()->{
                for(int i=0;i<10;i++){
                    Thread.sleep(100);
                    System.out.println("task2: " + i);

                }
                System.out.println("task2: END");
                return null;
            });
            for(int i=0;i<10;i++){
                Thread.sleep(100);
                System.out.println("task1: " + i);
            }
            System.out.println("task1: END");
            return null;
        });
	    Thread.sleep(500);
	    scope.shutdown();
	    System.out.println("scope: SHUTDOWN");
        scope.join();
    }catch (Exception e){
        System.out.println("Exception: " + e.getMessage());
    }

    System.out.println("--end--");
}

task2: 0
task1: 0
task2: 1
task1: 1
task2: 2
task1: 2
task2: 3
task1: 3
scope: SHUTDOWN
--end--

2. 协程 --Kotlin

private fun f() = runBlocking{
    println("--start--")

    val job1 = launch {
        launch {
            repeat(10){
                delay(100)
                println("job2: $it")
            }
            println("job2: END")
        }
        repeat(10){
            delay(100)
            println("job1: $it")
        }
        println("job1: END")
    }
    delay(500)
    job1.cancel()


    println("--end--")
}

--start--
job1: 0
job2: 0
job1: 1
job2: 1
job1: 2
job2: 2
job1: 3
job2: 3
--end-- 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值