多线程进阶学习02------Future异步任务

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 多线程进阶学习02------Future异步任务

异步任务即开辟分支任务,不阻塞主线程。Tips:异步线程的创建是纳秒级别

FutureTask

创建方式

// 创建任务对象
FutureTask<Integer> task3 = new FutureTask<>(() -> {
    return 100;
});
// 参数1 是任务对象; 参数2 是线程名字,推荐
new Thread(task3, "t3").start();
// 主线程阻塞,同步等待 task 执行完毕的结果
Integer result = task3.get();

缺点

1、获取值get阻塞

  • futureTask.get():get方法会阻塞主线程,一般要把get方法放到最后
  • futureTask.get(3,TimeUnit.SECONDS):假如我不愿意等待很长时间,过时不候直接抛出TimeOutException。
    其他程序调用的时候可以捕获超时异常,相当于变相的做了止损操作
FutureTask<Integer> task = new FutureTask<>(() -> {
    TimeUnit.SECONDS.sleep(10);
    return 100;
});
new Thread(task, "t3").start();
System.out.println(task.get());

2、轮训获取值isDone

  • 不断给主线程续命以等待异步线程的返回
  • 徒劳消耗cpu资源
FutureTask<Integer> task = new FutureTask<>(() -> {
    TimeUnit.SECONDS.sleep(10);
    return 100;
});
new Thread(task, "t3").start();
while (!task.isDone()) {
    System.out.println(task.get());
}

CompletableFuture

原有的FutureTask类,get()方法会导致阻塞,isDone()轮询也占用cpu,并且能用的api较少,对于以上缺点,jdk8推出了CompletableFuture。

  1. 在Java8中,CompletableFuture提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,并且提供了函数式编程的能力,可以通过回调的方式处理计算结果,也提供了转换和组合CompletableFuture的方法
  1. 它可能代表一个明确完成的Future,也有可能代表一个完成阶段(CompletionStage),它支持在计算完成以后触发一些函数或执行某些动作

案例展示

CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
    System.out.println(Thread.currentThread().getName() + "----come in");
    int result = ThreadLocalRandom.current().nextInt(10);
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("-----1秒钟后出结果:" + result);
    return result;
});
System.out.println(Thread.currentThread().getName() + "线程先去忙其它任务");
System.out.println(completableFuture.get());

四种创建方式

CompletableFuture 提供了四个静态方法来创建一个异步操作

  • runAsync方法不支持返回值.适用于多个接口之间没有任何先后关系
  • supplyAsync可以支持返回值,我们一般用supplyAsync来创建

比如在一个方法中,调用6个接口,接口A的结果需要作为接口B的入参,这个时候适合用带返回值的构造

//runAsync方法不支持返回值
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
//supplyAsync可以支持返回值
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同

public class CompletableFutureTest {
    public static void main(String[] args) throws Exception{
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2,
                5,
                2L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3));
        //(1). CompletableFuture.runAsync(Runnable runnable);
        CompletableFuture future1=CompletableFuture.runAsync(()->{
            System.out.println(Thread.currentThread().getName()+"*********future1 coming in");
        });
        //这里获取到的值是null
        System.out.println(future1.get());
        //(2). CompletableFuture.runAsync(Runnable runnable,Executor executor);
        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            //ForkJoinPool.commonPool-worker-9 
            System.out.println(Thread.currentThread().getName() + "\t" + "*********future2 coming in");
        }, executor);
        //(3).public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
        CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
            //pool-1-thread-1
            System.out.println(Thread.currentThread().getName() + "\t" + "future3带有返回值");
            return 1024;
        });
        System.out.println(future3.get());
        //(4).public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
        CompletableFuture<Integer> future4 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "future4带有返回值");
            return 1025;
        }, executor);
        System.out.println(future4.get());
        //关闭线程池
        executor.shutdown();
    }
}

获取结果

  1. public T get( ) 不见不散(会抛出异常) 只要调用了get( )方法,不管是否计算完成都会导致阻塞
  2. public T get(long timeout, TimeUnit unit) 过时不候
  3. public T getNow(T valuelfAbsent):没有计算完成的情况下,给我一个替代结果计算完,返回计算完成后的结果、没算完,返回设定的valuelfAbsent
  4. public T join( ):join方法和get( )方法作用一样,不同的是,join方法不抛出异常
  5. public boolean complete(T value) 是否打断get方法立刻返回括号值
private static void group1() throws InterruptedException, ExecutionException
    {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "abc";
        });
        //System.out.println(completableFuture.get());
        //System.out.println(completableFuture.get(2L,TimeUnit.SECONDS));
        //System.out.println(completableFuture.join());
        //暂停几秒钟线程
        try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
        //System.out.println(completableFuture.getNow("xxx"));
        System.out.println(completableFuture.complete("completeValue")+"\t"+completableFuture.get());
    }

处理计算结果

  1. public CompletableFuture thenApply 计算结果存在依赖关系,这两个线程串行化
    由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫停
  2. public CompletableFuture handle(BiFunction<? super T, Throwable, ? extends U> fn):有异常也可以往下一步走,根据带的异常参数可以进一步处理
  3. public CompletableFuture whenComplete( BiConsumer<? super T, ? super Throwable> action); 任务完成或者异常时运行action
  4. public CompletableFuture whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor); 任务完成或者异常时运行action,j可配置线程池
  5. public CompletableFuture exceptionally(Function<Throwable, ? extends T> fn); 有异常本次就会执行,否则不执行
ExecutorService threadPool = Executors.newFixedThreadPool(3);
        CompletableFuture.supplyAsync(() ->{
            //暂停几秒钟线程
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("111");
            return 1;
        },threadPool).handle((f,e) -> {
            int i=10/0;
            System.out.println("222");
            return f + 2;
        }).handle((f,e) -> {
            System.out.println("333");
            return f + 3;
        }).whenComplete((v,e) -> {
            if (e == null) {
                System.out.println("----计算结果: "+v);
            }
        }).exceptionally(e -> {
            e.printStackTrace();
            System.out.println(e.getMessage());
            return null;
        });
        System.out.println(Thread.currentThread().getName()+"----主线程先去忙其它任务");
        threadPool.shutdown();

whenComplete与handle的区别在于,它不参与返回结果的处理,把它当成监听器即可

即使异常被处理,在CompletableFuture外层,异常也会再次复现

消费计算结果

  1. thenRun(Runnable runnable) 任务A执行完执行B,并且B不需要A的结果
  2. CompletableFuture thenAccept(Consumer<? super T> action) 任务A执行完成执行B,B需要A的结果,但是任务B无返回值
  3. public CompletableFuture thenApply(Function<? super T,? extends U> fn) 任务A执行完成执行B,B需要A的结果,同时任务B有返回值
        CompletableFuture.supplyAsync(() -> {
            return 1;
        }).thenApply(f -> {
            return f+2;
        }).thenApply(f -> {
            return f+3;
        }).thenAccept(r -> System.out.println(r));
        // 任务A执行完执行B,并且B不需要A的结果
        System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenRun(() -> {}).join());
        // 任务A执行完成执行B,B需要A的结果,但是任务B无返回值
        System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenAccept(resultA -> {}).join());
        // 任务A执行完成执行B,B需要A的结果,同时任务B有返回值
        System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenApply(resultA -> resultA + " resultB").join());

对计算速度进行选用

public CompletableFuture applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)

这个方法表示的是,谁快就用谁的结果,类似于我们在打跑得快,或者麻将谁赢了就返回给谁

        //这个方法表示的是,谁快就用谁的结果,类似于我们在打跑得快,或者麻将谁赢了就返回给谁
        //public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn);
        //下面这个在第一个中停留1s,在第二种停留2s,返回的结果是1
        System.out.println(CompletableFuture.supplyAsync(() -> {
            //暂停几秒钟线程
            try { TimeUnit.SECONDS.sleep(1);  } catch (InterruptedException e) {e.printStackTrace();}
            return 1;
        }).applyToEither(CompletableFuture.supplyAsync(() -> {
            try { TimeUnit.SECONDS.sleep(2);  } catch (InterruptedException e) {e.printStackTrace();}
            return 2;
        }), r -> {
            return r;
        }).join());
        //暂停几秒钟线程
        try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }

applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值

acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值

runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返回值

对计算结果进行合并

public <U,V> CompletableFuture thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)

两个CompletionStage任务都完成后,最终把两个任务的结果一起交给thenCombine来处理

先完成的先等着,等待其他分支任务

        //public <U,V> CompletableFuture<V> thenCombine
        //(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)
        //两个CompletionStage任务都完成后,最终把两个任务的结果一起交给thenCombine来处理
        //先完成的先等着,等待其他分支任务
        System.out.println(CompletableFuture.supplyAsync(() -> {
            return 10;
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            return 20;
        }), (r1, r2) -> {
            return r1 + r2;
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            return 30;
        }), (r3, r4) -> {
            return r3 + r4;
        }).join());
        System.out.println(CompletableFuture.supplyAsync(() -> {
            return 10;
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            return 20;
        }), (r1, r2) -> {
            return r1 + r2;
        }).join());

两任务组合,都要完成

        CompletableFuture.supplyAsync(() -> {
            return 10;
        })
                .thenAcceptBoth(CompletableFuture.supplyAsync(() -> {
                    return 20;
                }), (r1, r2) -> {
                    System.out.println(r1);//10
                    System.out.println(r2);//20
                });

多任务组合

(public static CompletableFuture allOf(CompletableFuture<?>… cfs))

allOf:等待所有任务完成


(public static CompletableFuture anyOf(CompletableFuture<?>… cfs))

anyOf:只要有一个任务完成

 CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "hello.jpg";
        });
        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的属性");
            return "黑色+256G";
        });
        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            try { TimeUnit.SECONDS.sleep(3);  } catch (InterruptedException e) {e.printStackTrace();}
            System.out.println("查询商品介绍");
            return "华为";
        });
        //需要全部完成
//        futureImg.get();
//        futureAttr.get();
//        futureDesc.get();
        //CompletableFuture<Void> all = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
        //all.get();
        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
        anyOf.get();
        System.out.println(anyOf.get());
        System.out.println("main over.....");

案例演示

电商比价需求

同一款产品,同时搜索出同款产品在各大电商的售价;

同一款产品,同时搜索出本产品在某一个电商平台下,各个入驻门店的售价是多少

出来结果希望是同款产品的在不同地方的价格清单列表,返回一个List

in jd price is 88.05

in pdd price is 86.11

in taobao price is 90.43

public class CompletableFutureNetMallDemo {
    static List<NetMall> list = Arrays.asList(
            new NetMall("jd"),
            new NetMall("pdd"),
            new NetMall("taobao"),
            new NetMall("dangdangwang"),
            new NetMall("tmall"));
    //同步 ,step by step
    /**
     * List<NetMall>  ---->   List<String>
     * @param list
     * @param productName
     * @return
     */
    public static List<String> getPriceByStep(List<NetMall> list,String productName) {
        return list
                .stream()
                .map(netMall -> String.format(productName + " in %s price is %.2f", netMall.getMallName(),
                                netMall.calcPrice(productName)))
                .collect(Collectors.toList());
    }
    //异步 ,多箭齐发
    /**
     * List<NetMall>  ---->List<CompletableFuture<String>> --->   List<String>
     * @param list
     * @param productName
     * @return
     */
    public static List<String> getPriceByASync(List<NetMall> list,String productName) {
        return list
                .stream()
                .map(netMall ->
                        CompletableFuture.supplyAsync(() ->
                        String.format(productName + " is %s price is %.2f", netMall.getMallName(), netMall.calcPrice(productName)))
                )
                .collect(Collectors.toList())
                .stream()
                .map(CompletableFuture::join)
                .collect(Collectors.toList());
    }
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        List<String> list1 = getPriceByStep(list, "mysql");
        for (String element : list1) {
            System.out.println(element);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("----costTime: "+(endTime - startTime) +" 毫秒");
        System.out.println();
        long startTime2 = System.currentTimeMillis();
        List<String> list2 = getPriceByASync(list, "mysql");
        for (String element : list2) {
            System.out.println(element);
        }
        long endTime2 = System.currentTimeMillis();
        System.out.println("----costTime: "+(endTime2 - startTime2) +" 毫秒");
    }
}
@Data
@AllArgsConstructor
class NetMall {
    private String mallName;
    public double calcPrice(String productName) {
        //检索需要1秒钟
        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
        return ThreadLocalRandom.current().nextDouble() * 2 + productName.charAt(0);
    }
}
/*
  mysql in jd price is 110.59
  mysql in pdd price is 110.23
  mysql in taobao price is 110.04
  mysql in dangdangwang price is 110.08
  mysql in tmall price is 109.91
  ----costTime: 5030 毫秒
  mysql is jd price is 109.07
  mysql is pdd price is 109.47
  mysql is taobao price is 109.04
  mysql is dangdangwang price is 110.09
  mysql is tmall price is 110.72
  ----costTime: 1021 毫秒
**/

100个任务都返回一个数字且运行都要时间,使用多线程快速求和

三种写法,自我感受

package com.bilibili.juc.study;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;
/**
 * CompletableFuture 多任务合并
 */
public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();
        ArrayList<Integer> lists = new ArrayList<>();
        for (int i = 1; i <= 100; i++) {
            lists.add(1);
        }
        System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism","100");
        int sum = lists.stream().parallel().mapToInt(integer -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return integer;
        }).sum();
        System.out.println(sum);
        long end = System.currentTimeMillis();
        System.out.println("耗时:" + (end - start));
    }
    public static void fangshi1() {
        long start = System.currentTimeMillis();
        ExecutorService threadPool = Executors.newFixedThreadPool(50);
        ArrayList<Integer> lists = new ArrayList<>();
        for (int i = 1; i <= 100; i++) {
            lists.add(1);
        }
        int sum = lists.stream()
                .map(integer -> CompletableFuture.supplyAsync(() -> {
                    try {
                        TimeUnit.SECONDS.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return integer;
                }, threadPool))
                .collect(Collectors.toList())
                .stream()
                .map(CompletableFuture::join)
                .mapToInt(value -> value)
                .sum();
        System.out.println(sum);
        long end = System.currentTimeMillis();
        System.out.println("耗时:" + (end - start));
        threadPool.shutdown();
    }
    public static void fangshi2(){
        long start = System.currentTimeMillis();
        ExecutorService threadPool = Executors.newFixedThreadPool(100);
        ArrayList<Integer> lists = new ArrayList<>();
        for (int i = 1; i <= 100; i++) {
            lists.add(1);
        }
        List<CompletableFuture<Integer>> completableFutureList = lists.stream()
                .map(integer -> CompletableFuture.supplyAsync(() -> {
                    try {
                        TimeUnit.SECONDS.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return integer;
                }, threadPool))
                .collect(Collectors.toList());
        CompletableFuture<Void> completableFuture = CompletableFuture.allOf(completableFutureList
                .toArray(new CompletableFuture[completableFutureList.size()]));
        CompletableFuture<List<Integer>> listCompletableFuture = completableFuture.thenApply(v -> {
            return completableFutureList.stream().map(CompletableFuture::join).collect(Collectors.toList());
        });
        CompletableFuture<Long> longCompletableFuture = listCompletableFuture.thenApply(list -> {
            return list.stream().count();
        });
        System.out.println(longCompletableFuture.join());
        long end = System.currentTimeMillis();
        System.out.println("耗时:" + (end - start));
        threadPool.shutdown();
    }
}
    }


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
11天前
|
缓存 安全 Java
面试中的难题:线程异步执行后如何共享数据?
本文通过一个面试故事,详细讲解了Java中线程内部开启异步操作后如何安全地共享数据。介绍了异步操作的基本概念及常见实现方式(如CompletableFuture、ExecutorService),并重点探讨了volatile关键字、CountDownLatch和CompletableFuture等工具在线程间数据共享中的应用,帮助读者理解线程安全和内存可见性问题。通过这些方法,可以有效解决多线程环境下的数据共享挑战,提升编程效率和代码健壮性。
43 6
|
27天前
|
Java 调度 开发者
Java线程池ExecutorService学习和使用
通过学习和使用Java中的 `ExecutorService`,可以显著提升并发编程的效率和代码的可维护性。合理配置线程池参数,结合实际应用场景,可以实现高效、可靠的并发处理。希望本文提供的示例和思路能够帮助开发者深入理解并应用 `ExecutorService`,实现更高效的并发程序。
34 10
|
1月前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
109 17
|
3月前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
76 12
|
3月前
|
消息中间件 监控 Java
线程池关闭时未完成的任务如何保证数据的一致性?
保证线程池关闭时未完成任务的数据一致性需要综合运用多种方法和机制。通过备份与恢复、事务管理、任务状态记录与恢复、数据同步与协调、错误处理与补偿、监控与预警等手段的结合,以及结合具体业务场景进行分析和制定策略,能够最大程度地确保数据的一致性,保障系统的稳定运行和业务的顺利开展。同时,不断地优化和改进这些方法和机制,也是提高系统性能和可靠性的重要途径。
143 62
|
3月前
|
存储 Java 数据库
如何处理线程池关闭时未完成的任务?
总之,处理线程池关闭时未完成的任务需要综合考虑多种因素,并根据实际情况选择合适的处理方式。通过合理的处理,可以最大程度地减少任务丢失和数据不一致等问题,确保系统的稳定运行和业务的顺利开展。
173 64
|
4月前
|
安全 调度 C#
STA模型、同步上下文和多线程、异步调度
【10月更文挑战第19天】本文介绍了 STA 模型、同步上下文和多线程、异步调度的概念及其优缺点。STA 模型适用于单线程环境,确保资源访问的顺序性;同步上下文和多线程提高了程序的并发性和响应性,但增加了复杂性;异步调度提升了程序的响应性和资源利用率,但也带来了编程复杂性和错误处理的挑战。选择合适的模型需根据具体应用场景和需求进行权衡。
|
8天前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
38 17
|
17天前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
50 26
|
2月前
|
安全 Java API
【JavaEE】多线程编程引入——认识Thread类
Thread类,Thread中的run方法,在编程中怎么调度多线程