多线程进阶

ops/2024/10/18 18:21:53/

Start开启线程源码分析

  1. Thread.start开启线程
java">public class JUC01 {public static void main(String[] args) {Thread t1 = new Thread(() -> System.out.println("开启线程:"+Thread.currentThread().getName()),"t1");t1.start();}
}
  1. start方法源码
java">    public synchronized void start() {/*** This method is not invoked for the main method thread or "system"* group threads created/set up by the VM. Any new functionality added* to this method in the future may have to also be added to the VM.** A zero status value corresponds to state "NEW".*/if (threadStatus != 0)throw new IllegalThreadStateException();/* Notify the group that this thread is about to be started* so that it can be added to the group's list of threads* and the group's unstarted count can be decremented. */group.add(this);boolean started = false;try {start0();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {/* do nothing. If start0 threw a Throwable thenit will be passed up the call stack */}}}
  1. start方法中调用start0方法,start0方法是native方法,底层使用c++编写
java">private native void start0();

总结:

java线程是通过start的方法启动执行的,主要内容在native方法start0中,openjdk的写JNI一般是一一对应的,Thread.java对应的就是Thread.c,start0其实就是JVM_StartThread。此时查看源代码可以看到在jvm.h中找到了声明,jvm.cpp中有实现。

jvm配合操作系统,底层由操作系统分配了一个原生的基础线程。

image-20240421220958017

Future接口

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

FutureTask类

FutureTask实现了RunnableFuture接口,RunnableFuture接口实现了Runnable接口和Future接口,FutureTask有一个构造方法:FutureTask(Callable callable)

实现Runnable接口后,可以使用new Thread(Runnable r)开启多线程;

Future接口中有可以取消已启动的线程的方法;

FutureTask的构造方法FutureTask(Callable callable)使用构造注入的方式将Callable为自身所用,可以使用Callable接口的call方法编写多线程的逻辑,且call方法有返回值。

实例:

image-20240421233616447

FutureTask的缺点:

  1. get方法容易阻塞

image-20240422214310869

一般建议将get方法放在程序后面,假如不愿意等待很长时间,可以使用get(long timeout, TimeUnit unit)设置超时自动离开。

image-20240422215338251

  1. isDone轮询会耗费无谓的cpu资源,而且也不见得能及时地得到计算结果。

image-20240422220045893

结论:Future对于结果的获取不是很友好,只能通过阻塞或轮询的方式得到任务的结果。

CompletableFuture类

get方法阻塞的方式和异步编程的设计理念相违背,而轮询的方式会耗费无谓的CPU资源。因此,
JDK8设计出CompletableFuture。

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

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

java">public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {}

CompletionStage接口:

CompletionStage代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段,有些类似Linux系统的管道分隔符传参数:

  • CompletionStage代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段
  • 一个阶段的计算执行可以是一个Function,Consumer或Runnable。 比如:stage.thenApply(x -> square(x)).thenAccept(x -> System.out.print(x)).thenRun(() -> System.out.printin())
  • 一个阶段的执行可能是被单个阶段的完成触发,也可能是由多个阶段一起触发
四个静态方法

尽量不要使用构造方法获得CompletableFuture对象,尽量使用四个静态方法获取。

  1. 返回值为Void
java">public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor)
  1. 返回值为泛型U
java">public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor)

参数:

  • Executor:

没有传入指定的Executor,直接使用默认的ForkJoinPool.commonPool()作为它的线程池执行异步代码

如果指定线程池,则使用我们自定义的或者特别指定的线程池执行异步代码

  • Runnable:

传入Runnable的两个方法均无返回值

  • Supplier

供给型函数接口

image-20240422225448328

实例:

runAsync方法不传入线程池

image-20240422225043408

runAsync方法传入线程池

image-20240422225207834

supplyAsync方法不传入线程池

image-20240422225602925

image-20240422225634081

CompletableFuture的使用

从Java8开始引入了CompletableFuture,它是Future的功能增强版,减少阻塞和轮询,可以传入回调对象,当异步务完成或者发生异常时,自动调用回调对象的回调方法。

实例:

java">import java.util.concurrent.*;public class JUC01 {public static void main(String[] args) {//创建线程池ExecutorService threadPool = Executors.newFixedThreadPool(3);try {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;}, threadPool)//当上一步(supplyAsync)运行结束时执行whenComplete分支,v表示上一步返回的结果,e表示上一步出现的异常//注意:无论上一步(supplyAsync)是否出现异常,都会执行whenComplete分支.whenComplete((v, e) -> {if (e == null) { //上一步不出现异常时执行System.out.println("------计算完成,更新系统UpdateValue:" + v);}})//当上一步(supplyAsync)出现异常时执行exceptionally分支,e表示上一步出现的异常.exceptionally(e -> {e.printStackTrace();System.out.println("异常情况:" + e.getCause() + "\t" + e.getMessage());return null;});System.out.println(Thread.currentThread().getName()+"线程先去往其他任务");}catch (Exception e){e.printStackTrace();}finally {//关闭线程池threadPool.shutdown();}}
}

image-20240422234251424

注意:使用默认的线程池时,会把CompletableFuture.supplyAsync产生的线程设置为守护线程,当main线程结束时,守护线程也会随之结束。

优点

image-20240422234530765


http://www.ppmy.cn/ops/9980.html

相关文章

Python 网络与并发编程(一)

文章目录 并发编程介绍串行、并行与并发的区别进程、线程、协程的区别进程线程协程 并发编程解决方案同步和异步介绍 并发编程介绍 串行、并行与并发的区别 有任务A、B、C&#xff0c;一个CPU去执行他们&#xff0c;有几种方式 1、一个cpu按顺序执行ABC&#xff0c;这就是串行…

Elasticsearch单机部署(Linux)

1. 准备环境 本文中Elasticsearch版本为7.12.0&#xff0c;JDK版本为1.8.0&#xff0c;Linux环境部署。 扩展&#xff1a; &#xff08;1&#xff09;查看Elasticsearch对应的常用的jdk版本如下&#xff1a;&#xff08;详情可看官网的支持一览表&#xff09; Elasticsearch a…

iOS - Runloop在实际开发中的应用

文章目录 iOS - Runloop在实际开发中的应用1. 控制线程生命周期&#xff08;线程保活&#xff09;2. 解决NSTimer在滑动时停止工作的问题2.1. 案例2.2 解决 3. 监控应用卡顿4. 性能优化 iOS - Runloop在实际开发中的应用 1. 控制线程生命周期&#xff08;线程保活&#xff09;…

开源啦!一键部署免费使用!Kubernetes上直接运行大数据平台!

市场上首个K8s上的大数据平台&#xff0c;开源啦&#xff01; 智领云自主研发的首个 完全基于Kubernetes的容器化大数据平台 Kubernetes Data Platform (简称KDP) 开源啦&#x1f680;&#x1f680; 开发者只要准备好命令行工具&#xff0c;一键部署 Hadoop&#xff0c;Hi…

【前端】node.js常用命令

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、node是什么二、node.js常用命令三、总结 前言 随着开发语言及人工智能工具的普及&#xff0c;使得越来越多的人能够上手操作执行一些简单命令&#xff0c;…

milvus querynode启动源码分析

querynode启动源码分析 结构体 // QueryNode implements QueryNode grpc server // cmd\components\query_node.go type QueryNode struct {ctx context.Contextsvr *grpcquerynode.Server }// Server is the grpc server of QueryNode. type Server struct {querynode typ…

怎么通过Javascript脚本实现远程控制一路开关

怎么通过Javascript脚本实现远程控制一路开关呢&#xff1f; 本文描述了使用Javascript脚本调用HTTP接口&#xff0c;实现控制一路开关。一路开关可控制一路照明、排风扇等电器。 可选用产品&#xff1a;可根据实际场景需求&#xff0c;选择对应的规格 序号设备名称1智能WiFi…

3D开发工具HOOPS助力CAM软件优化制造流程

在现代制造业中&#xff0c;计算机辅助制造&#xff08;CAM&#xff09;软件的发展已成为提高生产效率和产品质量的关键。为了满足不断增长的需求和日益复杂的制造流程&#xff0c;CAM软件需要具备高效的CAD数据导入、云端协作、移动应用支持以及丰富的文档生成能力。 Tech So…