CompletableFuture异步编程多任务执行和简单场景使用

CompletableFuture提供了许多回调函数,来处理异步编程

获取任务结果方法

// 如果完成则返回结果,否则就抛出具体的异常
public T get() throws InterruptedException, ExecutionException // 最大时间等待返回结果,否则就抛出具体异常
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException// 完成时返回结果值,否则抛出unchecked异常。为了更好地符合通用函数形式的使用,如果完成此 CompletableFuture所涉及的计算引发异常,则此方法将引发unchecked异常并将底层异常作为其原因 不会强制开发者抛出。get()方法抛出的是经过检查的异常,ExecutionException, InterruptedException 需要用户手动处理(抛出或者 try catch)
public T join()// 如果完成则返回结果值(或抛出任何遇到的异常),否则返回给定的 valueIfAbsent。
public T getNow(T valueIfAbsent)// 如果任务没有完成,返回的值设置为给定值
public boolean complete(T value)// 如果任务没有完成,就抛出给定异常
public boolean completeExceptionally(Throwable ex) 

CompletableFuture创建异步任务

1:supplyAsync是创建带有返回值的异步任务。它有如下两个方法,一个是使用默认线程池(ForkJoinPool.commonPool())的方法(线程池大小和硬件有关),一个是带有自定义线程池的重载方法

// 带返回值异步请求,默认线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)// 带返回值的异步请求,可以自定义线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

2:runAsync是创建没有返回值的异步任务。它有如下两个方法,一个是使用默认线程池(ForkJoinPool.commonPool())的方法(线程池大小和硬件有关),一个是带有自定义线程池的重载方法

// 不带返回值的异步请求,默认线程池
public static CompletableFuture<Void> runAsync(Runnable runnable)// 不带返回值的异步请求,可以自定义线程池
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)

异步回调处理

1:thenApply(Function<T, U> fn)父子线程是同一个线程和thenApplyAsync(Function<T, U> fn)父子线程不是同一个线程: 对任务结果进行转换;表示某个任务执行完成后执行的动作,即回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,带有返回值

public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {//业务耗时任务System.out.println(Thread.currentThread() + " cf1 do something....");return 1;});//thenApply方法父线程按顺序执行,先执行完cf1的任务,再执行cf2CompletableFuture<Integer> cf2 = cf1.thenApply((result) -> {//业务耗时任务System.out.println(Thread.currentThread() + " cf2 do something....");result += 2;return result;});//会阻塞主线程,等待任务1执行完成System.out.println("cf1结果->" + cf1.get());//会阻塞主线程,等待任务2执行完成System.out.println("cf2结果->" + cf2.get());
}public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {//业务耗时任务System.out.println(Thread.currentThread() + " cf1 do something....");return 1;});//thenApplyAsync方法默认会阻塞父线程,等待父线程处理完再执行子线程CompletableFuture<Integer> cf2 = cf1.thenApplyAsync((result) -> {//业务耗时任务System.out.println(Thread.currentThread() + " cf2 do something....");result += 2;return result;});//会阻塞主线程,等待任务1执行完成System.out.println("cf1结果->" + cf1.get());//会阻塞主线程,等待任务2执行完成System.out.println("cf2结果->" + cf2.get());
}

2:thenAccept(Consumeraction)父子线程是同一个线程和thenAcceptAsync(Consumeraction)父子线程不是同一个线程: 对任务结果进行转换;表示某个任务执行完成后执行的动作,即回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,无返回值

public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {//业务耗时任务System.out.println(Thread.currentThread() + " cf1 do something....");return 1;});//thenAccept方法父线程按顺序执行,先执行完cf1的任务,再执行cf2CompletableFuture<Void> cf2 = cf1.thenAccept((result) -> {//业务耗时任务System.out.println(Thread.currentThread() + " cf2 do something....");});//会阻塞主线程,等待任务1执行完成System.out.println("cf1结果->" + cf1.get());//会阻塞主线程,等待任务2执行完成System.out.println("cf2结果->" + cf2.get());
}public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {//业务耗时任务System.out.println(Thread.currentThread() + " cf1 do something....");return 1;});//thenAcceptAsync方法默认会阻塞父线程,等待父线程处理完再执行子线程CompletableFuture<Void> cf2 = cf1.thenAcceptAsync((result) -> {//业务耗时任务System.out.println(Thread.currentThread() + " cf2 do something....");});//会阻塞主线程,等待任务1执行完成System.out.println("cf1结果->" + cf1.get());//会阻塞主线程,等待任务2执行完成System.out.println("cf2结果->" + cf2.get());
}

3:thenRun(Runnable action)父子线程是同一个线程和thenRunAsync(Consumeraction)父子线程不是同一个线程: 执行一个额外的任务,不依赖于任务结果;表示某个任务执行完成后执行的动作,即回调方法,无入参,无返回值

public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {//业务耗时任务System.out.println(Thread.currentThread() + " cf1 do something....");return 1;});//thenRun方法父线程按顺序执行,先执行完cf1的任务,再执行cf2CompletableFuture<Void> cf2 = cf1.thenRun(() -> {//业务耗时任务System.out.println(Thread.currentThread() + " cf2 do something....");});//会阻塞主线程,等待任务1执行完成System.out.println("cf1结果->" + cf1.get());//会阻塞主线程,等待任务2执行完成System.out.println("cf2结果->" + cf2.get());
}public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {//业务耗时任务System.out.println(Thread.currentThread() + " cf1 do something....");return 1;});//thenRunAsync方法默认会阻塞父线程,等待父线程处理完再执行子线程CompletableFuture<Void> cf2 = cf1.thenRunAsync(() -> {//业务耗时任务System.out.println(Thread.currentThread() + " cf2 do something....");});//会阻塞主线程,等待任务1执行完成System.out.println("cf1结果->" + cf1.get());//会阻塞主线程,等待任务2执行完成System.out.println("cf2结果->" + cf2.get());
}

双任务组合处理,将两个CompletableFuture组合起来处理,只有两个任务都正常完成时,才进行下阶段任务

1:thenCombine会将两个任务的执行结果作为所提供函数的参数,且该方法有返回值

public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf1 do something....");return 1;});CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf2 do something....");return 2;});CompletableFuture<Integer> cf3 = cf1.thenCombine(cf2, (a, b) -> {System.out.println(Thread.currentThread() + " cf3 do something....");return a + b;});//打印获取到两个结果相加的值为3System.out.println("cf3结果->" + cf3.get());
}

2:thenAcceptBoth同样将两个任务的执行结果作为方法入参,但是无返回值

 public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf1 do something....");return 1;});CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf2 do something....");return 2;});CompletableFuture<Void> cf3 = cf1.thenAcceptBoth(cf2, (a, b) -> {System.out.println(Thread.currentThread() + " cf3 do something....");System.out.println(a + b);});//无返回值,打印结果为nullSystem.out.println("cf3结果->" + cf3.get());
}

3:runAfterBoth没有入参,也没有返回值。注意两个任务中只要有一个执行异常,则将该异常信息作为指定任务的执行结果

public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf1 do something....");return 1;});CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf2 do something....");return 2;});CompletableFuture<Void> cf3 = cf1.runAfterBoth(cf2, () -> {System.out.println(Thread.currentThread() + " cf3 do something....");});//无返回值,打印结果为nullSystem.out.println("cf3结果->" + cf3.get());
}

双任务组合处理,将两个CompletableFuture组合起来处理,有一个任务正常完成时,就会进行下阶段任务

1:applyToEither会将已经完成任务的执行结果作为所提供函数的参数,且该方法有返回值

    public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(1000*2);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread() + " cf1 do something....");return 1;});CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf2 do something....");return 2;});CompletableFuture<Integer> cf3 = cf1.applyToEither(cf2, (result) -> {System.out.println(Thread.currentThread() + " cf3 do something....");return result;});//打印2System.out.println("cf3结果->" + cf3.get());}

2:acceptEither同样将已经完成任务的执行结果作为方法入参,但是无返回值

 public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf1 do something....");return 1;});CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf2 do something....");return 2;});CompletableFuture<Void> cf3 = cf1.acceptEither(cf2, (a, b) -> {System.out.println(Thread.currentThread() + " cf3 do something....");System.out.println(a + b);});//无返回值,打印结果为nullSystem.out.println("cf3结果->" + cf3.get());
}

3:runAfterEither没有入参,也没有返回值

public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf1 do something....");return 1;});CompletableFuture<Integer> cf2 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf2 do something....");return 2;});CompletableFuture<Void> cf3 = cf1.runAfterEither(cf2, () -> {System.out.println(Thread.currentThread() + " cf3 do something....");});//无返回值,打印结果为nullSystem.out.println("cf3结果->" + cf3.get());
}

合并多个CompletableFuture

1:allOf:CompletableFuture是多个任务都执行完成后才会执行,只要有一个任务执行异常,则返回的CompletableFuture执行get方法时会抛出相应任务的异常,如果都是正常执行,则get返回null

public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {try {System.out.println(Thread.currentThread() + " cf1 do something....");Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("cf1 任务完成");return "cf1 任务完成";});CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {try {System.out.println(Thread.currentThread() + " cf2 do something....");int a = 1/0;Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("cf2 任务完成");return "cf2 任务完成";});CompletableFuture<Void> cfAll = CompletableFuture.allOf(cf1, cf2);//如果cf1和cf2都执行成功,cfAll.get()返回的是nullSystem.out.println("cfAll结果->" + cfAll.get());
}

2:anyOf :CompletableFuture是多个任务只要有一个任务执行完成,则返回的CompletableFuture执行get方法时会抛出异常,如果都是正常执行,则get返回执行完成任务的结果

public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {try {System.out.println(Thread.currentThread() + " cf1 do something....");Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("cf1 任务完成");return "cf1 任务完成";});CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {try {System.out.println(Thread.currentThread() + " cf2 do something....");Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("cf2 任务完成");return "cf2 任务完成";});//get,执行先返回执行任务成功的结果CompletableFuture<Object> cfAll = CompletableFuture.anyOf(cf1, cf2);System.out.println("cfAll结果->" + cfAll.get());
}

异常完成处理,如果任务执行过程中抛出了异常,可以使用以下方法处理异常

1:exceptionally(Function<Throwable, T> fn): 在任务抛出异常时提供一个默认值;

    public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf1 do something....");int a = 1/0;return 1;});CompletableFuture<Integer> cf2 = cf1.exceptionally(ex -> {System.out.println("Exception: " + ex.getMessage());return 0;});//注意:如果使用cf1.get(),发送异常的话,就会被get()方法抛出去,不会执行cf1.exceptionally的方法//System.out.println("cf1结果->" + cf1.get());//有异常,结果就打印异常回调设置的默认值,不会抛出异常System.out.println("cf2结果->" + cf2.get());}

2:whenComplete和whenCompleteAsync,whenComplete是当某个任务执行完成后执行的回调方法,会将执行结果或者执行期间抛出的异常传递给回调方法,如果是正常执行则异常为null,回调方法对应的CompletableFuture的result和该任务一致,如果该任务正常执行,则get方法返回执行结果,如果是执行异常,则get方法抛出异常

 public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf1 do something....");int a = 1/0;return 1;});CompletableFuture<Integer> cf2 = cf1.whenComplete((result, e) -> {System.out.println("上个任务结果:" + result);System.out.println("上个任务抛出异常:" + e);System.out.println(Thread.currentThread() + " cf2 do something....");});//        //等待任务1执行完成
//        System.out.println("cf1结果->" + cf1.get());
//        //等待任务2执行完成System.out.println("cf2结果->" + cf2.get());}

3:handle和handleAsync,跟whenComplete方法基本一致,区别在于handle的回调方法有返回值,如果有异常会被抛出

public static void main(String[] args) throws ExecutionException, InterruptedException {CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {System.out.println(Thread.currentThread() + " cf1 do something....");// int a = 1/0;return 1;});CompletableFuture<Integer> cf2 = cf1.handle((result, e) -> {System.out.println(Thread.currentThread() + " cf2 do something....");System.out.println("上个任务结果:" + result);System.out.println("上个任务抛出异常:" + e);return result+2;});//等待任务2执行完成System.out.println("cf2结果->" + cf2.get());
}

CompletableFuture 和 Future的区别

Future 接口只提供了 get() 方法来获取计算结果,但如果计算时间过长,我们的线程就会一直堵塞,要等待 10年才会打印值,Future 也没有任何方法可以手动完成任务,例子如下

import java.util.concurrent.*;public class FutureDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService executor = Executors.newSingleThreadExecutor();Future<String> future = executor.submit(() -> threadSleep());System.out.println("The result is: " + future.get());}private static String threadSleep() throws InterruptedException {TimeUnit.DAYS.sleep(365 * 10);return "finishSleep";}
}

CompletableFuture提供complete() 方法可以手动完成任务解决Future的弊端,示例代码如下:

import java.util.concurrent.*;public class CompletableFutureDemo {public static void main(String[] args) {CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> threadSleep());completableFuture.complete("Completed");System.out.println("result: " + completableFuture.get());System.out.println("completableFuture done ? " + completableFuture.isDone());}private static String threadSleep(){try {TimeUnit.DAYS.sleep(365 * 10);} catch (InterruptedException e) {throw new RuntimeException(e);}return "finishSleep";}
}

使用 Future 接口,我们无法异步组合这两个操作,只能同步完成,示例代码如下:

import java.util.concurrent.*;public class FutureDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService executor = Executors.newSingleThreadExecutor();Future<Integer> firstFuture = executor.submit(() -> firstMethod(1));int firstMethodResult = firstFuture.get(); // 获取 firstMethod的结果值System.out.println("firstMethodResult:" + firstMethodResult);Future<Integer> secondFuture = executor.submit(() -> secondMethod(firstMethodResult));System.out.println("secondMethodResult:" + secondFuture.get());executor.shutdown();}private static int firstMethod(int num) {return num;}private static int secondMethod(int firstMethodResult) {return 2 + firstMethodResult;}
}

在上述示例代码中:

CompletableFuture 是在不阻塞主线程的前提下,异步组合两个操作过程

import java.util.concurrent.*;public class CompletableFutureDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {var finalResult = CompletableFuture.supplyAsync(() -> firstMethod(1)).thenApply(firstMethodResult -> secondMethod(firstMethodResult));System.out.println("finalResult:" + finalResult.get());}private static int firstMethod(int num) {return num;}private static int secondMethod(int firstMethodResult) {return 2 + firstMethodResult;}
}

在上述示例代码中:

注意CompletableFuture 异步关于异常的坑

程序存在异常,却返回成功,结果:接口返回成功,控制台没有打印错误信息,如下代码

/*** 异步执行异常测试*/
@ApiOperation(value = "异步执行异常测试", code = 800)
@GetMapping("/asyncException")
public ResponseData<Object> asyncException() {try {try {CompletableFuture.runAsync(() -> {int i = 1 / 0;});} catch (Exception e) {log.error("异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());}return new ResponseData<>(StatusCodeEnum.SUCCESS_CODE.getStatusCode(), "操作成功");} catch (Exception e) {return new ResponseData<>(StatusCodeEnum.ERROR_CODE.getStatusCode(), "操作失败:" + e.getMessage());}
}

解决方法一:异步调用join(),结果:接口返回失败,控制台打印异常日志

// join方法获取异常信息: 将异步线程中发生的异常信息抛到主线程, 这样异常可被主线程捕获
try {CompletableFuture.runAsync(() -> {int i = 1 / 0;}, CUSTOM_THREAD_POOL).join();
} catch (Exception e) {log.error("外层异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());
}

解决方法二:异步调用get(),异步方法中get()是阻塞的,在使用时要设置超时时间,结果:接口返回成功,控制台打印异常信息

// get方法获取异常信息: 将异步线程中发生的异常信息抛到主线程, 这样异常可被主线程捕获
try {CompletableFuture.runAsync(() -> {int i = 1 / 0;}, CUSTOM_THREAD_POOL).get(2, TimeUnit.SECONDS);
} catch (Exception e) {log.error("外层异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());
}

解决方法三:异步调用exception(),结果:接口返回成功,控制台打印异步线程异常日志,主线程没有打印异常日志

// exceptionally获取异常信息: 异常是存在于异步当中的, 不能被主线程捕获
try {CompletableFuture.runAsync(() -> {int i = 1 / 0;}, CUSTOM_THREAD_POOL).exceptionally(e -> {log.error("异步运行异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());});
} catch (Exception e) {log.error("异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());
}

解决方法四:异步调用whenComplete(),结果:结果返回成功,控制台打印异步线程异常信息,主线程没有打印异常信息

// whenComplete获取异常信息: 异常是存在于异步当中的, 不能被主线程捕获
try {CompletableFuture.runAsync(() -> {int i = 1 / 0;}, CUSTOM_THREAD_POOL).whenComplete((r, e) -> {if (e != null) {log.error("异步执行异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());}});
} catch (Exception e) {log.error("异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());
}

解决方法五:异步调用handle(),结果:结果返回成功,控制台打印异步线程异常信息,主线程没有打印异常信息

// handle获取异常信息: 异常是存在于异步当中的, 不能被主线程捕获
try {CompletableFuture.runAsync(() -> {int i = 1 / 0;}, CUSTOM_THREAD_POOL).handle((r, e) -> {if (e != null) {log.error("异步执行异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());}return null;});
} catch (Exception e) {log.error("异常信息: " + e.getMessage(), e);throw new BusinessException(e.getMessage());
}

总结:在使用异步CompletableFuture时,无论是否有返回值都要调用get()/join()方法,避免程序执行报错了,仍然返回成功。如果在程序报错时需要对上一个异步任务结果做其他操作,可以调用whenComplete()、handle()处理,如果只是对异常做处理,不涉及对上一个异步任务结果的情况,调用exceptionally()处理

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

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

相关文章

NFS服务器环境搭建

1、什么是NFS ● 定义&#xff1a; NFS是一种在计算机系统之间共享文件和目录的协议&#xff0c;最初由Sun Microsystems开发&#xff0c;现在已经成为广泛使用的网络文件系统之一。 ● 核心功能&#xff1a; 通过网络&#xff08;特别是TCP/IP网络&#xff09;实现文件共享…

探索Conda环境的迷宫:conda env list命令全解析

&#x1f4dc; 探索Conda环境的迷宫&#xff1a;conda env list命令全解析 Conda不仅是Python编程生态中强大的包管理器&#xff0c;还是一个高效的环境管理器。它允许用户创建隔离的环境&#xff0c;每个环境可以拥有不同版本的库和工具&#xff0c;从而避免版本冲突并提高开…

微信小程序配置访问服务器失败所发现的问题及解决方案

目录 事前现象问题1&#xff1a;问题现象&#xff1a;问题分析&#xff1a; 问题2&#xff1a;问题现象&#xff1a;问题分析&#xff1a;解决方案&#xff1a; 事后现象 事前现象 问题1&#xff1a; 问题现象&#xff1a; 在本地调试时&#xff0c;一切顺利&#xff0c;但一…

MySQL:送分or送命 varchar(30) 与 int(10)

摘要&#xff1a; VARCHAR(30) 和 INT(10) 在MySQL中代表两种不同类型的字段&#xff0c;它们之间的主要区别在于它们存储的数据类型、存储方式以及显示宽度的含义。 正文&#xff1a; INT(10) 在MySQL中&#xff0c;当你看到INT(10)这样的数据类型定义时&#xff0c;可能会…

LeetCode707 设计链表

前言 题目&#xff1a; 707. 设计链表 文档&#xff1a; 代码随想录——设计链表 编程语言&#xff1a; C 解题状态&#xff1a; 代码功底不够&#xff0c;只能写个大概 思路 主要考察对链表结构的熟悉程度&#xff0c;对链表的增删改查&#xff0c;比较考验代码功底以及对链表…

Flink Doirs Connector 常见问题:Doris目前不支持流读

常见问题 Doris Source 在数据读取完成后&#xff0c;流为什么就结束了&#xff1f; 目前 Doris Source 是有界流&#xff0c;不支持 CDC 方式读取。 问题&#xff1a;对于 Flink Doris DataStream&#xff0c;Flink 想要在 流式读取 Doirs / 实时读 Doris&#xff0c;目前读…

03--KVM虚拟化

前言&#xff1a;这里开始涉及到云计算内容&#xff0c;虚拟化使云计算发展&#xff0c;云计算推动虚拟化进步&#xff0c;两者相辅相成&#xff0c;这一章总结一下kvm虚拟化的解决方案。 1、基础概念 1.1、云计算 以前要完成信息处理, 是需要在一个客观存在的计算机上完成的…

Node.js版本管理工具之NVM

目录 一、NVM介绍二、NVM的下载安装1、NVM下载2、卸载旧版Node.js3、安装 三、NVM配置及使用1、设置nvm镜像源2、安装Node.js3、卸载Node.js4、使用或切换Node.js版本5、设置全局安装路径和缓存路径 四、常用命令技术交流 博主介绍&#xff1a; 计算机科班人&#xff0c;全栈工…

卷积神经网络(一)---原理和结构

在介绍卷积神经网络之前&#xff0c;先提出三个观点&#xff0c;正是这三个观点使得卷积神经网络能够真正起作用。 1. 局部性 对于一张图片而言&#xff0c;需要检测图片中的特征来决定图片的类别&#xff0c;通常情况下这些特征都不是由整张图片决定的&#xff0c;而是由一些…

vscode 环境

这张截图显示的是在VS Code&#xff08;Visual Studio Code&#xff09;中选择Python解释器的界面。不同的Python解释器及其虚拟环境列出了可选项&#xff0c;用户可以根据需要选择合适的解释器来运行Python代码。以下是对截图中信息的详细解释&#xff1a; 解释器选择界面 当…

构造方法 继续学习~

python类可以使用&#xff1a;__init__()方法&#xff0c;称为构造方法。 可以实现&#xff1a; 在创建类对象时&#xff0c;会自动执行 在创建类对象时&#xff0c;将传入参数自动传递给__init__()方法使用 # 构造方法的名称:__init__ class Student:name Noneage Nonet…

前后端分离真的好吗?

我们经常看到一些页面很卡&#xff0c;是由于前后断分离技术导致的&#xff0c;大量数据都由后端提供&#xff0c;甚至包括字体大小&#xff0c;边距。 每次后端都要搬一个大箱子过来&#xff0c;能不慢吗&#xff1f;如果出现这种问题&#xff0c;怎么解决呢&#xff1f; 首先…

Chrome浏览器设置暗黑模式 - 护眼模式 - 亮度调节 - DarkReader - 地址栏和书签栏设置为黑色背景

效果图 全黑 浅灰 &#xff08;DarkReader设置开启亮色亮度-25&#xff09; 全白 前言 主要分两部分需要操作&#xff0c; 1&#xff09;地址栏和书签栏 》 需要修改浏览器的外观模式 2&#xff09;页面主体 》 需要安装darkreader插件进行设置 步骤 1&#xff09;地址栏和…

spring 中的注解操作

在 spring 中&#xff0c;对注解的操作&#xff0c;都位于 spring-core 模块下的 org.springframework.core.annotation 包中。通过 annotation 包中定义的相关类&#xff0c;完成对类型、方法、字段等元素上注解的操作。 主要类介绍 MergedAnnotations 接口&#xff0c;为 …

Java21的主要新特性总结

目录 概述 变动说明 重要变更和信息 下载地址 Java21新特性总结 1、JEP 441: Switch 的模式匹配&#xff08;正式特性&#xff09; 功能进化 Switch 模式匹配 类型标签 null标签 守卫标签 使用enum常量作值 语法总结 2、JEP 440&#xff1a;Record模式&#xff08…

常用工具类

常用工具类 date类 日期设置方法 方法 描述 setDate() 以数值&#xff08;1-31&#xff09;设置日 setFullYear() 设置年&#xff08;可选月和日&#xff09; setHours() 设置小时&#xff08;0-23&#xff09; setMilliseconds() 设置毫秒&#xff08;0-999&#x…

AOP面向切面编程和log4j的使用(Java版)

什么是面向切面编程 在传统的面向对象编程中&#xff0c;程序的功能被模块化成各个类和方法&#xff0c;这些类和方法分别处理特定的功能。然而&#xff0c;有些功能可能涉及到多个类、多个方法&#xff0c;例如日志记录、事务管理、性能监控等&#xff0c;这些功能可能在不同…

橙单后端项目下载编译遇到的问题与解决

今天下载orange-admin项目&#xff0c;不过下载下来运行出现一些问题。 1、涉及到XMLStreamException的几个类都出现下面的错误 The package javax.xml.stream is accessible from more than one module: <unnamed>, java.xml ctrl-shift-t 可以找到这个引入是哪些包里…

AcWing803. 区间合并

#include<climits>的作用是方便我直接使用INT_MIN,下面这个代码是二刷写的 思路是先根据 [ L , R ] i [L,R]_i [L,R]i​的L先排序&#xff0c;然后遍历vector进行区间合并。 #include<iostream> #include<vector> #include<algorithm> #include<cl…

在window将Redis注册为服务

将redis注册为系统服务&#xff0c;开启自启动 安装服务 默认注册完之后会自动启动&#xff0c;在window中的服务看一下&#xff0c;如果启动类型为自动&#xff0c;状态是自动运行则启动完成。如果是手动&#xff0c;需要右键属性调整为自动&#xff0c;在点击启动&#xff0c…