基本概念。
进程:运行在操作系统上的程序,如QQ和IDE。
线程:一个进程可以有多个线程,例如同时收听声音、图像和弹幕。
多线程:多个线程并发执行。
同步:通过人工控制和调度,保证对共享资源的多线程访问是线程安全的,以保证结果的准确性,如同步关键字,在保证结果准确性的同时提高性能,线程安全优先级高于性能。
并行性:多个 CPU 实例或多台机器同时执行一段处理逻辑。
并发性:通过CPU调度算法,用户看似同时执行,但实际上从CPU操作层面来看,其实并不是同时执行的。
线程的生命周期。
新状态:当程序使用 new 关键字创建线程时,该线程处于新状态,只有 JVM 为其分配内存并初始化其成员变量的值。
就绪状态:当线程对象调用 start() 方法时,线程处于就绪状态。 j**a 虚拟机创建一个方法调用堆栈和程序计数器,以便计划运行。
运行状态:如果处于就绪状态的线程获取 CPU 并开始执行 run() 方法,则该线程处于运行状态。
阻塞状态:当处于运行状态的线程失去占用的资源时,进入阻塞状态。
死态:线程在执行 run() 方法后进入死态。 此外,如果线程执行 interrupt() 或 stop() 方法,那么它也会进入死状态并异常退出。
线程池。 什么是线程池?
一个可以容纳多个线程的容器,其中线程可以重复使用,无需频繁创建线程对象,重复创建线程会消耗过多的系统资源。
为什么要使用线程池?
创建线程的方法有两种,一种是继承线程类,另一种是实现 runnable 接口,实际上就是 runnable 接口。 但是,这两个线程在运行结束时都会被 JVM 销毁,如果线程很多,频繁创建和销毁线程会浪费内存。 那么有没有办法让线程在运行完后不立即被销毁,而是让线程复用并继续执行其他任务呢?
这就是线程池的由来,是线程复用的好办法,避免了重复开销。
线程池任务执行过程。
线程池的优点。
1.线程是稀缺资源,使用线程池可以减少线程的创建和销毁次数,并且每个工作线程都可以重复使用。
2、可根据系统容差调整线程池中的工作线程数,防止服务器因内存消耗过大而崩溃。
线程池参数。
拒绝策略预定义有四种类型:
1)AbortPolicy(默认策略):当线程池的任务队列已满,线程池内所有线程都忙时,会直接拒绝新提交的任务,并抛出rejectedexecution异常。
2)CallerRunsPolicy:当线程池的任务队列已满且线程池中的线程繁忙时,新提交的任务将由提交任务的线程所在的线程池执行。也就是说,当前线程将直接执行任务。
3)DiscardOldestPolicy:当线程池的任务队列已满且线程池中的线程繁忙时,将丢弃队列中最早的任务,并尝试将新提交的任务添加到队列中。
4)DiscardPolicy:当线程池的任务队列已满且线程池中的线程繁忙时,不进行任何处理即可丢弃新提交的任务。
future
运行线程时可以有两种形式,一种具有返回值,另一种没有返回值。 当我们得到一个正在运行的线程的返回值时,我们需要将其与 future 结合使用。
您可以使用 futures 将任务提交到线程池执行,并在需要时获取任务的执行结果。 其主要目的是允许主线程在提交异步任务后继续执行其他操作,而无需等待任务完成。 它可以提高系统的并发性和响应能力。 但是,获得结果很容易导致堵塞。
以下是未来接口的一些常用方法:
1) Boolean cancel(Boolean Mayinterruptifrunning):取消任务的执行。如果正在执行任务,并且 MayInterruptifRunning 参数设置为 true,则尝试中断任务的执行。
2) boolean iscancelled():检查任务是否已取消。
3) boolean isdone():判断任务是否已经完成。
4) v get() 抛出 interruptedexception, executionexception: 获取任务的执行结果。如果任务尚未执行,则 get() 方法将阻塞,直到任务执行完毕。 如果在任务执行过程中发生异常,get() 方法会抛出 executionexception,您可以使用 getcause() 方法获取具体的异常信息。
4) V get(long timeout, timeunit unit) 抛出 interruptedException, executionException, TimeOutException: 获取任务在指定时间内的执行结果,如果任务未在指定时间内执行,则抛出 timeoutException 异常。
ExecutorService 的 submit 方法。
ExecutorService 是 J**A 提供的用于管理线程池的接口。 它可用于执行异步任务和管理线程的生命周期。 submit 方法是由 ExecutorService 接口定义的方法,它将任务提交到线程池并获取将来的对象来表示任务的执行结果。
具体来说,submit 方法用于将可调用或可运行的对象提交到线程池进行执行。 可调用对象是有结果的任务,而可运行对象是没有结果的任务。 submit 方法将任务提交到线程池,并立即返回一个 future 对象,通过该对象可以获取任务执行的结果或取消任务的执行。
您可以通过 submit 方法轻松管理线程池中的任务,也可以使用 future 对象获取任务的状态和结果,也可以取消任务的执行。 通常,我们可以使用 submit 方法而不是 execute 方法,因为它具有更多的功能和灵活性。
submit 和 execute 之间的区别。
submit() 和 execute() 是 ExecutorService 接口用于将任务提交到线程池的两种方法,它们有以下区别:
1)返回值类型不同:submit()方法返回一个未来对象,可用于获取任务的执行结果或取消任务的执行;另一方面,execute() 方法不返回值,也无法获取任务执行的结果。
2)不同的异常处理:submit()方法可以捕获任务执行过程中抛出的异常,将异常封装到以后的对象中,通过调用get()方法或get(long, timeunit)方法获取任务的执行结果,如果任务抛出异常,可以通过executionexception获取异常信息;execute() 方法无法处理任务引发的异常,如果任务引发异常,线程池会将异常记录到控制台。
3)不同的参数类型:submit()方法接受可调用或可运行的对象作为参数,可调用是有返回值的任务,runnable是没有返回值的任务;execute() 方法只接受可运行对象作为参数。 因此,如果你需要获取任务执行的结果,你应该使用 submit() 方法,如果你不需要获取结果,你可以使用 execute() 方法。
一般来说,submit() 方法比 execute() 方法更灵活,可以获取任务的执行结果并捕获任务中抛出的异常,因此在处理需要获取结果或处理异常的任务时,建议使用 submit() 方法。 对于不需要结果的简单任务,可以使用 execute() 方法。
completablefuture
未来使用阻塞来获取结果与异步编程的设计理念背道而驰,轮询方式会消耗不必要的 CPU 资源,因此 jdk8 设计了 completablefuture。
CompletableFuture保留了未来的优点,弥补了其不足。 也就是说,当异步任务完成并且您需要继续操作其结果时,您无需等待。 可以直接使用 thenaccept、thenapply、thencompose 等方式,将之前异步处理的结果交给另一个异步事件处理线程进行处理。
CompletableFuture 对 get 方法的调用也将被阻止以获取结果。
1. 创建异步任务。
创造一个可完成的未来
CompleTableFuture 提供了四种静态方法来创建异步操作。
未指定执行程序的方法使用 forkjoinpoolcommonpool() 作为其线程池异步执行。
如果指定了线程池,则使用指定的线程池。
runasync 方法不支持返回值。
SupplyAsync 可以支持返回值。
任务是异步的。
thenrun/thenrunasync
可完成的未来thenrun/thenrunasync通俗地说,方法是完成第一个任务,然后做第二个任务。 也就是说,一个任务执行完成后,执行**方法; 但是,第一个和第二个任务没有参数传递,第二个任务也没有返回值。
thenrun 和 thenrunasync 有什么区别?
如果在执行第一个任务时没有传入自定义线程池,则 thenrun thenrunasync 自然会使用默认的内置 forkjoin 线程池,并且可能都使用相同的线程。
相反,如果执行第一个任务,则传入自定义线程池:
当调用 thenrun 方法执行第二个任务时,第二个任务和第一个任务共享同一个线程池,因此可以使用相同的线程。
调用 thenrunasync 执行第二个任务时,第一个任务使用您自己的线程池,第二个任务使用分叉连接线程池。
注意:thenaccept 和 thenacceptasync、thenapply 和 thenapplyasync 等的区别与 thenrun 和 thenrunasync 相同。
thenaccept/thenacceptasync
completablefuture 的 thenaccept ThenAcceptAsync 方法表示,第一个任务执行完毕后,执行第二个方法任务,但第一个任务的执行结果会作为输入参数传递给该方法,但该方法没有返回值。
thenapply/thenapplyasync
completablefuture 的 thenapply thenapplyasync 方法表示,第一个任务执行完毕后,执行第二个方法任务,但第一个任务的执行结果会作为输入参数传递给该方法,并且该方法有一个返回值。
exceptionally
completablefuture 的 exceptionally 方法表示当任务执行异常时,执行 ** 处理方法,抛出异常作为参数传递给 ** 方法,并且 ** 方法具有返回值。
whencomplete
completablefuture 的 whencomplete 方法表示,在执行一个任务后,执行了 ** 方法,并将任务结果用作 ** 方法的输入参数,** 方法没有返回值,whencomplete 方法返回的 completablefuture 的结果是第一个任务的结果。
handle
completablefuture 的 handle 方法表示执行一个任务后,执行 ** 方法,并将任务结果用作 ** 方法的输入参数,** 方法有一个返回值,handle 方法返回的 completablefuture 结果是 ** 方法的执行结果。
handle 和 thenapply 之间的区别。
thenapply:当任务发生异常时不,它不会转到然后申请
handle:任务异常是的输入句柄以处理异常。
3.多任务组合**。
和投资组合关系。
ThenCombine ThenAcceptBoth RunAfterBorne 表示:当任务 1 和任务 2 都完成时,将执行任务 3。
不同之处在于 runafterboth 不使用结果作为方法参数,也不返回值。
ThenAcceptBoth:将两个任务的执行结果作为方法参数传递给指定的方法,并且没有返回值。
thencombine:将两个任务的执行结果作为方法参数传递给指定的方法,并有一个返回值。
或组合关系。
applytoeither accepteither runafter两者都表示:两个任务,只要完成一个任务,就会执行第三个任务
区别在于:runaftereither:执行结果不作为方法参数使用,没有返回值。
accepteither:已完成的任务将作为方法输入参数传递给指定的方法,不带返回值。
applytoeither:完成的任务将作为带有返回值的方法输入参数传递给指定的方法。
多任务组合。
「allof」:等待所有任务完成并执行新任务。
「anyof」:完成一项任务后,将执行一项新任务。
4.completablefuture的使用注意事项。
1)future需要获取返回值来获取异常信息。
future 需要获取返回值来获取异常信息。 如果不添加 get() join() 方法,请考虑是否添加 try...。catch...或者使用 exceptionally 方法。
2) completablefuture 的 get() 方法被阻止。
completablefuture 的 get() 方法是阻塞的,如果用它来获取异步调用的返回值,则需要添加超时。
3)线程池的注意事项。
可以在 completablefuture 中使用默认线程池。 当大量请求传入时,如果处理逻辑复杂,响应速度会很慢。 一般情况下,建议您使用自定义线程池来优化线程池配置参数。
future 与 completablefuture。
未来:我们的目标是获得异步任务的结果,但对于未来,我们只能通过使用 get 方法或无限循环来判断是否完成。 异常情况更难处理。
completablefuture:只要我们设置了 ** 函数,就可以实现:
1.任务一完成,我们设置的功能就被执行了(无需考虑任务何时完成)。
2.如果发生异常,将执行处理异常的相同函数,甚至是默认返回值(更耗费人力)。
如果你有复杂的任务,比如依赖问题、组合问题等,也可以写一个处理函数来处理它(可以处理复杂的任务)。
当前 ** 问题。
1. 使用 Spring 线程池,统一管理线程。
如果接口频繁访问,则每次访问都会创建一个新的线程池,这可能会导致访问时间过长和内存耗尽。
如果不调用 shutdown() 方法关闭线程池,可能会导致资源泄漏,或者程序可能无法正常退出。
Spring 线程池。
使用 thenaccept of completablefuture 可以避免阻塞。
在这种情况下,主线程不需要获取返回值,先完成将附件保存到服务器的任务,然后将第一个任务的“文件路径”作为第二个任务的输入参数存储在 fjxx 表中。
completablefuture 使用自定义线程池。
设置超时时间。
invokeall() 方法的超时时间与每个任务的执行时间没有直接关系,因此在使用 invokeall() 方法时,需要根据任务数量和执行时间合理设置超时时间,以避免出现超时时间过长或过短的情况, 这会导致程序性能下降或任务无法完成。
调用未来后get() 方法获取任务执行结果时,还可以设置超时时间和时间单位,防止整个程序因任务执行时间过长而做出响应。
冗余逻辑。
2月** 动态激励计划