并发编程02:CompletableFuture

news2024/11/16 14:20:35

文章目录

  • 2.1 Future接口理论知识
  • 2.2 Future接口常用实现类FutureTask异步任务
    • 2.2.1 Future接口能干什么
    • 2.2.2 Future接口相关架构
    • 2.2.3 Future编码实战和优缺点分析
    • 2.2.4 完成一些复杂的任务
  • 2.3 CompletableFuture对Future的改进
    • 2.3.1 CompletableFuture为什么会出现
    • 2.3.2 CompletableFuture和CompletionStage介绍
    • 2.3.3 核心的四个静态方法,来创建一个异步任务
  • 2.4 案例----电商网站的比价需求
    • 2.4.1 函数式编程已成为主流
    • 2.4.2 大厂业务需求说明
    • 2.4.3 比价案例实战
    • 2.4.4 CompletableFuture常用方法

2.1 Future接口理论知识

Future接口(FutureTask实现类)定义了操作异步任务执行一些方法,如获取异步任务的执行结果、取消异步任务的执行、判断任务是否被取消、判断任务执行是否完毕等。

举例:比如主线程让一个子线程去执行任务,子线程可能比较耗时,启动子线程开始执行任务后,主线程就去做其他事情了,忙完其他事情或者先执行完,过了一会再才去获取子任务的执行结果或变更的任务状态(老师上课时间想喝水,他继续讲课不结束上课这个主线程,让学生去小卖部帮老师买水完成这个耗时和费力的任务)。
在这里插入图片描述

2.2 Future接口常用实现类FutureTask异步任务

2.2.1 Future接口能干什么

Future是Java5新加的一个接口,它提供一种异步并行计算的功能,如果主线程需要执行一个很耗时的计算任务,我们会就可以通过Future把这个任务放进异步线程中执行,主线程继续处理其他任务或者先行结束,再通过Future获取计算结果。

2.2.2 Future接口相关架构

目的:异步多线程任务执行且返回有结果,三个特点:多线程、有返回、异步任务(班长为老师去买水作为新启动的异步多线程任务且买到水有结果返回)
代码实现:Runnable接口+Callable接口+Future接口和FutureTask实现类。
在这里插入图片描述
FutureTask开启异步任务

public class CompletableFutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> futureTask = new FutureTask(new MyThread());
        Thread t1 = new Thread(futureTask); //开启一个异步线程
        t1.start();

        System.out.println(futureTask.get()); //有返回hello Callable
    }
}


class MyThread implements Callable<String> {

    @Override
    public String call() throws Exception {
        System.out.println("--------come in");
        return "hello Callable";
    }
}

2.2.3 Future编码实战和优缺点分析

  • 优点:Future+线程池异步多线程任务配合,能显著提高程序的运行效率。
  • 缺点:
    • get()阻塞—一旦调用get()方法求结果,一旦调用不见不散,非要等到结果才会离开,不管你是否计算完成,如果没有计算完成容易程序堵塞。
    • isDone()轮询—轮询的方式会耗费无谓的cpu资源,而且也不见得能及时得到计算结果,如果想要异步获取结果,通常会以轮询的方式去获取结果,尽量不要阻塞。
  • 结论:Future对于结果的获取不是很友好,只能通过阻塞或轮询的方式得到任务的结果。
    Future获取结果get()和轮询
public class FutureApiDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        FutureTask<String> futureTask = new FutureTask<>(() -> {
            System.out.println(Thread.currentThread().getName() + "--------come in");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "task over";
        });

        Thread t1 = new Thread(futureTask, "t1");
        t1.start();

//        System.out.println(futureTask.get());//这样会有阻塞的可能,在程序没有计算完毕的情况下。
        System.out.println(Thread.currentThread().getName() + " ------忙其他任务");
//        System.out.println(futureTask.get(3,TimeUnit.SECONDS));//只愿意等待三秒,计算未完成直接抛出异常
        while (true) {//轮询
            if(futureTask.isDone()){
                System.out.println(futureTask.get());
                break;
            }else{
                TimeUnit.MILLISECONDS.sleep(500);
                System.out.println("正在处理中,不要催了,越催越慢");
            }
        }
        /* 轮询结果
        * main ------忙其他任务
        t1--------come in
        正在处理中,不要催了,越催越慢
        正在处理中,不要催了,越催越慢
        正在处理中,不要催了,越催越慢
        正在处理中,不要催了,越催越慢
        正在处理中,不要催了,越催越慢
        正在处理中,不要催了,越催越慢
        正在处理中,不要催了,越催越慢
        正在处理中,不要催了,越催越慢
        正在处理中,不要催了,越催越慢
        正在处理中,不要催了,越催越慢
        task over
        Process finished with exit code 0
        * */
    }
}

2.2.4 完成一些复杂的任务

  • 对于简单的业务场景使用Future完全ok
  • 回调通知:
    • 应对Future的完成时间,完成了可以告诉我,也就是我们的回调通知
    • 通过轮询的方式去判断任务是否完成这样非常占cpu并且代码也不优雅
  • 创建异步任务:Future+线程池组合
  • 多个任务前后依赖可以组合处理(水煮鱼—>买鱼—>调料—>下锅):
    • 想将多个异步任务的结果组合起来,后一个异步任务的计算结果需要钱一个异步任务的值
    • 想将两个或多个异步计算合并成为一个异步计算,这几个异步计算互相独立,同时后面这个又依赖前一个处理的结果
  • 对计算速度选最快的:
    • 当Future集合中某个任务最快结束时,返回结果,返回第一名处理结果
  • 结论:
    • 使用Future之前提供的那点API就囊中羞涩,处理起来不够优雅,这时候还是让CompletableFuture以声明式的方式优雅的处理这些需求。
    • 从i到i++
    • Future能干的,CompletableFuture都能干

2.3 CompletableFuture对Future的改进

2.3.1 CompletableFuture为什么会出现

  • get()方法在Future计算完成之前会一直处在阻塞状态下,阻塞的方式和异步编程的设计理念相违背。
  • isDene()方法容易耗费cpu资源(cpu空转),
  • 对于真正的异步处理我们希望是可以通过传入回调函数,在Future结束时自动调用该回调函数,这样,我们就不用等待结果

jdk8设计出CompletableFuture,CompletableFuture提供了一种观察者模式类似的机制,可以让任务执行完成后通知监听的一方。

2.3.2 CompletableFuture和CompletionStage介绍

类架构说明:
在这里插入图片描述

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

2.3.3 核心的四个静态方法,来创建一个异步任务

四个静态构造方法

在这里插入图片描述

对于上述Executor参数说明:若没有指定,则使用默认的ForkJoinPoolcommonPool()作为它的线程
池执行异步代码,如果指定线程池,则使用我们自定义的或者特别指定的线程池执行异步代码

四个静态方法演示

public class CompletableFutureBuildDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },executorService);

        System.out.println(completableFuture.get()); //null


        CompletableFuture<String> objectCompletableFuture = CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello supplyAsync";
        },executorService);

        System.out.println(objectCompletableFuture.get());//hello supplyAsync

        executorService.shutdown();

    }
}

CompletableFuture减少阻塞和轮询,可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法。

CompletableFuture使用演示

public class CompletableFutureUseDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        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();
            }
            if (result > 5) { //模拟产生异常情况
                int i = 10 / 0;
            }
            System.out.println("----------1秒钟后出结果" + result);
            return result;
        }, executorService).whenComplete((v, e) -> {
            if (e == null) {
                System.out.println("计算完成 更新系统" + v);
            }
        }).exceptionally(e -> {
            e.printStackTrace();
            System.out.println("异常情况:" + e.getCause() + " " + e.getMessage());
            return null;
        });
        System.out.println(Thread.currentThread().getName() + "先去完成其他任务");
        executorService.shutdown();
    }
}

/**
 * 无异常情况
 * pool-1-thread-1---come in
 * main先去完成其他任务
 * ----------1秒钟后出结果9
 * 计算完成 更新系统9
 */

/**
 * 有异常情况
 *pool-1-thread-1---come in
 * main先去完成其他任务
 * java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
 * 异常情况:java.lang.ArithmeticException: / by zero java.lang.ArithmeticException: / by zero
 */

CompletableFuture优点:

  • 异步任务结束时,会自动回调某个对象的方法
  • 主线程设置好回调后,不用关心异步任务的执行,异步任务之间可以顺序执行
  • 异步任务出错时,会自动回调某个对象的方法

2.4 案例----电商网站的比价需求

2.4.1 函数式编程已成为主流

Lambda表达式+Stream流式调用+Chain链式调用+Java8函数式编程
函数时接口:

  • Runnable:无参数、无返回值
    在这里插入图片描述

  • Function:接受一个参数,并且有返回值
    在这里插入图片描述

  • Consumer:接受一个参数,没有返回值
    在这里插入图片描述

  • BiConsumer:接受两个参数,没有返回值
    在这里插入图片描述

  • Supplier:没有参数,有返回值
    在这里插入图片描述

小结:
在这里插入图片描述

chain链式调用:

public class CompletableFutureMallDemo {
    public static void main(String[] args) {
        Student student = new Student();
        student.setId(1).setStudentName("z3").setMajor("english"); //链式调用
    }
}


@AllArgsConstructor
@NoArgsConstructor
@Data
@Accessors(chain = true)//开启链式调用
class Student {
    private Integer id;
    private String studentName;
    private String major;
}

2.4.2 大厂业务需求说明

切记:功能—>性能(完成—>完美)
电商网站比价需求分析:

  1. 需求说明:
    • 同一款产品,同时搜索出同款产品在各大电商平台的售价
    • 同一款产品,同时搜索出本产品在同一个电商平台下,各个入驻卖家售价是多少
  2. 输出返回:
    • 出来结果希望是同款产品的在不同地方的价格清单列表,返回一个List
      例如:《Mysql》 in jd price is 88.05 《Mysql》 in taobao price is 90.43
  3. 解决方案,对比同一个产品在各个平台上的价格,要求获得一个清单列表
    • step by step,按部就班,查完淘宝查京东,查完京东查天猫…
    • all in,万箭齐发,一口气多线程异步任务同时查询

2.4.3 比价案例实战

public class CompletableFutureMallDemo {
    static List<NetMall> list = Arrays.asList(new NetMall("jd"), new NetMall("taobao"), new NetMall("dangdang"));

    /**
     * step by step
     * @param list
     * @param productName
     * @return
     */
    public static List<String> getPrice(List<NetMall> list, String productName) {
        //《Mysql》 in jd price is 88.05
        return list
                .stream()
                .map(netMall ->
                        String.format("《" + productName + "》" + "in %s price is %.2f",
                                netMall.getNetMallName(),
                                netMall.calcPrice(productName)))
                .collect(Collectors.toList());
    }

    /**
     * all in
     * 把list里面的内容映射给CompletableFuture()
     * @param list
     * @param productName
     * @return
     */
    public static List<String> getPriceByCompletableFuture(List<NetMall> list, String productName) {
        return list.stream().map(netMall ->
                        CompletableFuture.supplyAsync(() ->
                                String.format("《" + productName + "》" + "in %s price is %.2f",
                                        netMall.getNetMallName(),
                                        netMall.calcPrice(productName)))) //Stream<CompletableFuture<String>>
                .collect(Collectors.toList()) //List<CompletableFuture<String>>
                .stream()//Stream<String>
                .map(s -> s.join()).collect(Collectors.toList()); //List<String>
    }

    public static void main(String[] args) {
        /**
         * 采用step by setp方式查询
         * 《masql》in jd price is 110.11
         * 《masql》in taobao price is 109.32
         * 《masql》in dangdang price is 109.24
         * ------costTime: 3094 毫秒
         */
        long StartTime = System.currentTimeMillis();
        List<String> list1 = getPrice(list, "masql");
        for (String element : list1) {
            System.out.println(element);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("------costTime: " + (endTime - StartTime) + " 毫秒");

        /**
         * 采用 all in三个异步线程方式查询
         * 《mysql》in jd price is 109.71
         * 《mysql》in taobao price is 110.69
         * 《mysql》in dangdang price is 109.28
         * ------costTime1009 毫秒
         */
        long StartTime2 = System.currentTimeMillis();
        List<String> list2 = getPriceByCompletableFuture(list, "mysql");
        for (String element : list2) {
            System.out.println(element);
        }
        long endTime2 = System.currentTimeMillis();
        System.out.println("------costTime" + (endTime2 - StartTime2) + " 毫秒");

    }
}

@AllArgsConstructor
@NoArgsConstructor
@Data
class NetMall {
    private String netMallName;

    public double calcPrice(String productName) {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return ThreadLocalRandom.current().nextDouble() * 2 + productName.charAt(0);
    }
}

2.4.4 CompletableFuture常用方法

获得结果和触发计算

  • 获取结果
    • public T get()
    • public T get(long timeout,TimeUnit unit)
    • public T join() —>和get一样的作用,只是不需要抛出异常
    • public T getNow(T valuelfAbsent) —>计算完成就返回正常值,否则返回备胎值(传入的参数),立即获取结果不阻塞
  • 主动触发计算
    • public boolean complete(T value) ---->是否打断get方法立即返回括号值

对计算结果进行处理

  • thenApply —>计算结果存在依赖关系,这两个线程串行化---->由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫停
  • handle —>计算结果存在依赖关系,这两个线程串行化---->有异常也可以往下走一步

对计算结果进行处理演示

public class CompletableFutureApiDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1;
        }, threadPool).thenApply(f -> {
            System.out.println("222");
            return f + 2;
        }).handle((f, e) -> {
            System.out.println("3333");
            int i=10/0;
            return f + 2;

//             thenApply(f -> {
//            System.out.println("3333");
//            return f + 2;
        }).whenComplete((v, e) -> {
            if (e == null) {
                System.out.println("----计算结果" + v);
            }
        }).exceptionally(e -> {
            e.printStackTrace();
            System.out.println(e.getCause());
            return null;
        });
        System.out.println(Thread.currentThread().getName() + "------主线程先去做其他事情");
    }
}

对计算结果进行消费

  • 接受任务的处理结果,并消费处理,无返回结果
  • thenAccept

thenAccetp演示

public class CompletableFutureApi2Demo {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        CompletableFuture.supplyAsync(() -> {
            return 1;
        }, threadPool).thenApply(f -> {
            return f + 2;
        }).thenApply(f -> {
            return f + 2;
        }).thenAccept(r -> {
            System.out.println(r);//5
        });
    }
}
  • 对比补充
    • thenRun(Runnable runnable) :任务A执行完执行B,并且不需要A的结果
    • thenAccept(Consumer action): 任务A执行完执行B,B需要A的结果,但是任务B没有返回值
    • thenApply(Function fn): 任务A执行完执行B,B需要A的结果,同时任务B有返回值

对比补充

public class CompletableFutureApi2Demo {
    public static void main(String[] args) {
        System.out.println(CompletableFuture.supplyAsync(() -> "result").thenRun(() -> {}).join());//null
        System.out.println(CompletableFuture.supplyAsync(() -> "result").thenAccept(r -> System.out.println(r)).join());//result null
        System.out.println(CompletableFuture.supplyAsync(() -> "result").thenApply(f -> f + 2).join());//result2
    }
}
  • CompletableFuture和线程池说明
    • 如果没有传入自定义线程池,都用默认线程池ForkJoinPool
    • 传入一个线程池,如果你执行第一个任务时,传入了一个自定义线程池
      • 调用thenRun方法执行第二个任务时,则第二个任务和第一个任务时共用同一个线程池
      • 调用thenRunAsync执行第二个任务时,则第一个任务使用的是你自定义的线程池,第二个任务使用的是ForkJoin线程池
    • 备注:可能是线程处理太快,系统优化切换原则, 直接使用main线程处理,thenAccept和thenAcceptAsync,thenApply和thenApplyAsync等,之间的区别同理。

对计算速度进行选用

  • 谁快用谁
  • applyToEither

applyToEither演示

public class CompletableFutureApiDemo {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        CompletableFuture<String> playA = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("A come in");
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "playA";
        }, threadPool);


        CompletableFuture<String> playB = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("B come in");
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "playB";
        }, threadPool);

        CompletableFuture<String> result = playA.applyToEither(playB, f -> {
            return f + " is winner";
        });

        /**
         * A come in
         * B come in
         * main-----------winner:playA is winner
         */
        System.out.println(Thread.currentThread().getName() + "-----------winner:" + result.join());
    }
}

对计算结果进行合并

  • 两个CompletableStage任务都完成后,最终能把两个任务的结果一起交给thenCombine来处理
  • 先完成的先等着,等待其他分支任务

thenCombine演示

public class CompletableFutureApi3Demo {
    public static void main(String[] args) {
        CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " 启动");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 10;
        });

        CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " 启动");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 20;
        });

        CompletableFuture<Integer> finalResult = completableFuture1.thenCombine(completableFuture2, (x, y) -> {
            System.out.println("----------开始两个结果合并");
            return x + y;
        });
        System.out.println(finalResult.join());

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/493415.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis持久化篇

文章目录 持久化篇1、AOF持久化是怎么实现的&#xff1f;1.1、AOF日志1.2、三种写回策略1.3、AOF重写机制1.4、AOF后台重写 2、RDB快照是怎么实现的&#xff1f;2.1、快照怎么使用2.2、执行快照时&#xff0c;数据能被修改吗&#xff1f;2.3、RDB和AOF合体 3、Redis大key对持久…

自动驾驶行业观察之2023上海车展-----智驾供应链(2)

传感器供应链发展 图达通&#xff1a;展示长距Lidar“Falcon”&#xff0c;和DeepWay签署定点协议 产品&#xff1a;主视激光雷达 Falcon 猎鹰&#xff08;2023CES曾亮相&#xff09; 核心亮点&#xff1a; • 核心性能&#xff1a;最远探测距离可达 500 米&#xff0c;为智…

《计算机网络—自顶向下方法》 第一章Wireshark实验:Wireshark软件的安装和入门

要深入理解网络协议&#xff0c;需要仔细观察协议实体之间交换的报文序列。为探究协议操作细节&#xff0c;可使协议实体执行某些动作&#xff0c;观察这些动作及其影响。这些任务可以在仿真环境下或在如因特网这样的真实网络环境中完成。观察在正在运行协议实体间交换报文的基…

万字长文详解linux内存管理,值得收藏

一、Linux内存管理概述 Linux内存管理是指对系统内存的分配、释放、映射、管理、交换、压缩等一系列操作的管理。在Linux中&#xff0c;内存被划分为多个区域&#xff0c;每个区域有不同的作用&#xff0c;包括内核空间、用户空间、缓存、交换分区等。Linux内存管理的目标是最…

经典常用的脚本讲解

目录 一&#xff1a;echo 语句 二&#xff1a;while read命令​编辑 三&#xff1a;猴子摘香蕉问题 四:斐波拉切数求前10个数的和 ​五&#xff1a;随机生成8位数的密码 六&#xff1a;二进制转换 &#xff08;1&#xff09;余数倒排法 &#xff08;2&#xff09;减法正…

Google - ISLR 比赛总结

引言 本篇主要想总结一下最近打的GISLR比赛&#xff0c;本来是没想写的&#xff0c;比赛前期感觉赛题很有意思&#xff0c;做了eda以及根据一些base改了改自己的方案&#xff0c;取得了还不错的结果&#xff0c;但因为中途被各种琐事缠身&#xff0c;发生了很多变故&#xff0…

【Linux】Libevent库

Libevent——高性能I/O框架库 底层封装了select&#xff0c;poll&#xff0c;epoll&#xff0c;便于使用 I/O框架库以库函数的形式&#xff0c;封装了较为底层的系统调用&#xff0c;给应用程序提供了一组更便于使用的接口。 特点&#xff1a;1.跨平台&#xff0c;2.统一事件源…

c++面向对象之封装、继承、和多态

一、封装 把客观事物封装成类&#xff0c;而且可以把自己的数据和方法设置为只能让可信的类或者对象操作&#xff0c;对不可信的信息进行隐藏&#xff08;利用public,private,protected,friend)实现 二、继承 2.1类与类的关系 has-a &#xff1a;描述一个类由多个部件类构成…

SpringCloud全面学习笔记之初尝美妙篇

目录 前言初识微服务单体架构分布式架构微服务架构初见SpringCloud微服务治理分布式服务架构案例 微服务组件及使用Eureka注册中心提供者和消费者Eureka的结构和作用搭建Eureka服务注册服务服务发现Eureka注册服务总结 Ribbon负载均衡原理负载均衡原理负载均衡策略懒加载 Nacos…

Qt quick基础2(包含平移旋转放缩以及qml控件大写开头啊)

Qt quick基础2&#xff08;包含平移旋转放缩以及qml控件大写开头啊&#xff09; 目录 Qt quick基础2&#xff08;包含平移旋转放缩以及qml控件大写开头啊&#xff09;前言简单的平移、旋转和放缩其他元素的一些基本使用qml文件作为控件时&#xff0c;务必以大写字母开头命名小结…

力扣题库刷题笔记682-棒球比赛

1、题目如下&#xff1a; 2、个人Python代码实现如下&#xff1a; 代码如下&#xff1a; class Solution: def calPoints(self, operations: List[str]) -> int: i 0 #用于遍历元素的下标 while i < len(operations): …

【Python入门篇】——Python基础语法(数据类型与数据类型转换)

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; Python入门&#xff0c;本专栏主要内容为Python的基础语法&#xff0c;Python中的选择循环语句…

数据结构与算法导学

文章目录 数据结构和算法导学认识数据结构认识算法总结 数据结构和算法导学 程序 数据结构 算法 认识数据结构 什么是数据结构&#xff1f; 数据结构是一门研究计算机中数据存储和数据操作的学科。 为什么要学习数据结构&#xff1f; 学习数据结构能让我们写出更加优秀的代码…

关于在线帮助中心你需要思考以下几个问题

搭建帮助中心是大多数企业都在尝试做的事情&#xff0c;它的重要性对于企业来说不言而喻。现在对于企业来说&#xff0c;搭建帮助中心或许不是什么难事&#xff0c;但是关于帮助中心&#xff0c;有几个问题需要思考清楚&#xff0c;才能让其发挥最大的价值。 一、如何让用户养成…

CAS 原子操作类

CAS 原子类 java.util.concurrent.atomic 是什么 CAS compare and swap的缩写&#xff0c;中文翻译比较并交换&#xff0c;实现并发算法时常用的一种技术 它包含三个操作数–内存位置、预期原值及更新值 执行CAS操作时&#xff0c;将内存位置的值与预期原值比较 如果相匹…

网络协议与攻击模拟-05-ICMP协议

ICMP 协议 1、理解 ICMP 协议 2、理解 ICMP 重定向 3、会使用 wireshark 分析 ICMP 重定向流量实验 一、 ICMP 基本概念 1、 ICMP 协议 Internet 控制报文协议&#xff0c;用于在 IP 主机、路由器之间传递控制消息&#xff0c;控制消息指网络通不通、主机是否可达、路由是否…

荔枝派Zero(全志V3S)驱动开发之hello驱动程序

文章目录 前言一、设备驱动分类二、字符设备驱动简介三、字符设备驱动开发1、APP打开的文件在内核中如何表示2、编写驱动程序的步骤3、hello 驱动程序编写<1>、试验程序编写<2>、测试程序编写<3>、编写 Makefile<4>、编译 3、运行测试<1>、上传程…

PyTorch实战4:猴痘病识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考文章&#xff1a;365天深度学习训练营-第P4周&#xff1a;猴痘病识别&#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 目录 一、搭建CNN网络结构1、原文网络结构1.1、网络…

4。计算机组成原理(2)存储系统

嵌入式软件开发&#xff0c;非科班专业必须掌握的基本计算机知识 核心知识点&#xff1a;数据表示和运算、存储系统、指令系统、总线系统、中央处理器、输入输出系统 这一部分主要讲解了CPU的组成和扩容、CPU与存储器&#xff08;主存、辅存、缓存&#xff09;的连接 一 存储…

C++笔记——第十六篇 异常

目录 1.C语言传统的处理错误的方式 2. C异常概念 3. 异常的使用 3.1 异常的抛出和捕获 在函数调用链中异常栈展开匹配原则 3.2异常安全 4.异常的优缺点 1.C语言传统的处理错误的方式 传统的错误处理机制&#xff1a; 1. 终止程序&#xff0c;如assert&#xff0c;缺陷&a…