【Java面试】第七天

在这里插入图片描述

🌟个人主页:时间会证明一切.


目录

  • 有三个线程T1,T2,T3如何保证顺序执行?
    • 依次执行start方法
    • 使用join
    • 使用CountDownLatch
    • 使用线程池
    • 使用CompletableFuture
  • Spring Bean的生命周期是怎么样的?
  • Autowired和Resource的关系?
    • 相同点
    • 不同点
      • byName和byType匹配顺序不同
      • 作用域不同
      • 支持方不同

有三个线程T1,T2,T3如何保证顺序执行?

想要让三个线程依次执行,并且严格按照T1,T2,T3的顺序的话,主要就是想办法让三个线程之间可以通信、或者可以排队。

想让多个线程之间可以通信,可以通过join方法实现,还可以通过CountDownLatch、CyclicBarrier和Semaphore来实现通信。

想要让线程之间排队的话,可以通过线程池或者CompletableFuture的方式来实现。

依次执行start方法

在代码中,分别依次调用三个线程的start方法,这种方法是最容易想到的,但是也是最不靠谱的。

代码实现如下,通过执行的话可以发现,数据结果是不固定的:

    public static void main(String[] args) {Thread thread1 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("Thread 1 running");}});Thread thread2 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("Thread 2 running");}});Thread thread3 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("Thread 3 running");}});thread1.start();thread2.start();thread3.start();}

以上代码的数据结果每次执行都不固定,所以,没办法满足我们的要求。

使用join

Thread类中提供了一个join方法,他的有以下代码:

public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread 1 running");}});thread1.start();System.out.println("Main 1 running");
}


输出结果会是:

Main 1 running
Thread 1 running

但是,如果我们在上面的第15行,增加一行thread1.join();那么输出结果就会有变化,如下:

Thread 1 running
Main 1 running

所以,join就是把thread1这个子线程加入到当前主线程中,也就是主线程要阻塞在这里,等子线程执行完之后再继续执行。

所以,我们可以通过join来实现多个线程的顺序执行:

    public static void main(String[] args) {final Thread thread1 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " is Running.");}},"T1");final Thread thread2 = new Thread(new Runnable() {@Overridepublic void run() {try {thread1.join();} catch (InterruptedException e) {System.out.println("join thread1 failed");}System.out.println(Thread.currentThread().getName() + " is Running.");}},"T2");Thread thread3 = new Thread(new Runnable() {@Overridepublic void run() {try {thread2.join();} catch (InterruptedException e) {System.out.println("join thread1 failed");}System.out.println(Thread.currentThread().getName() + " is Running.");}},"T3");thread3.start();thread2.start();thread1.start();}

我们在thread2中等待thread1执行完,然后在thread3中等待thread2执行完。那么整体的执行顺序就是:

T1 is Running.
T2 is Running.
T3 is Running.

使用CountDownLatch

CountDownLatch是Java并发库中的一个同步辅助类,它允许一个或多个线程等待其他线程完成操作。我们可以借助他来让三个线程之间相互通信,以达到顺序执行的目的。

public class CountDownLatchThreadExecute {public static void main(String[] args) throws InterruptedException {// 创建CountDownLatch对象,用来做线程通信CountDownLatch latch = new CountDownLatch(1);CountDownLatch latch2 = new CountDownLatch(1);CountDownLatch latch3 = new CountDownLatch(1);// 创建并启动线程T1Thread t1 = new Thread(new MyThread(latch), "T1");t1.start();// 等待线程T1执行完latch.await();// 创建并启动线程T2Thread t2 = new Thread(new MyThread(latch2), "T2");t2.start();// 等待线程T2执行完latch2.await();// 创建并启动线程T3Thread t3 = new Thread(new MyThread(latch3), "T3");t3.start();// 等待线程T3执行完latch3.await();}
}class MyThread implements Runnable {private CountDownLatch latch;public MyThread(CountDownLatch latch) {this.latch = latch;}@Overridepublic void run() {try {// 模拟执行任务Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + " is Running.");} catch (InterruptedException e) {e.printStackTrace();} finally {// 完成一个线程,计数器减1latch.countDown();}}
}

主要就是想办法让编排三个子线程的主线程阻塞,保证T1执行完再启动T2,T2执行完再启动T3。而这个编排的方式就是想办法知道什么时候子线程执行完,就可以通过CountDownLatch实现。

基于相同的原理, 我们还可以借助CyclicBarrier和Semaphore实现此功能:

public class CyclicBarrierThreadExecute {public static void main(String[] args) throws InterruptedException, BrokenBarrierException {// 创建CyclicBarrier对象,用来做线程通信CyclicBarrier barrier = new CyclicBarrier(2);// 创建并启动线程T1Thread t1 = new Thread(new MyThread(barrier), "T1");t1.start();// 等待线程T1执行完barrier.await();// 创建并启动线程T2Thread t2 = new Thread(new MyThread(barrier), "T2");t2.start();// 等待线程T2执行完barrier.await();// 创建并启动线程T3Thread t3 = new Thread(new MyThread(barrier), "T3");t3.start();// 等待线程T3执行完barrier.await();}
}class MyThread implements Runnable {private CyclicBarrier barrier;public MyThread(CyclicBarrier barrier) {this.barrier = barrier;}@Overridepublic void run() {try {// 模拟执行任务Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + " is Running.");} catch (InterruptedException e) {e.printStackTrace();} finally {// 等待其他线程完成try {barrier.await();} catch (Exception e) {e.printStackTrace();}}}
}

借助Semaphore实现此功能:

public class SemaphoreThreadExecute {public static void main(String[] args) throws InterruptedException {// 创建Semaphore对象,用来做线程通信Semaphore semaphore = new Semaphore(1);// 等待线程T1执行完semaphore.acquire();// 创建并启动线程T1Thread t1 = new Thread(new MyThread(semaphore), "T1");t1.start();// 等待线程T2执行完semaphore.acquire();// 创建并启动线程T2Thread t2 = new Thread(new MyThread(semaphore), "T2");t2.start();// 等待线程T3执行完semaphore.acquire();// 创建并启动线程T3Thread t3 = new Thread(new MyThread(semaphore), "T3");t3.start();}
}class MyThread implements Runnable {private Semaphore semaphore;public MyThread(Semaphore semaphore) {this.semaphore = semaphore;}@Overridepublic void run() {try {// 模拟执行任务Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + " is Running.");} catch (InterruptedException e) {e.printStackTrace();} finally {// 释放许可证,表示完成一个线程semaphore.release();}}
}

使用线程池

了解线程池的开发者都知道,线程池内部是使用了队列来存储任务的,所以线程的执行顺序会按照任务的提交顺序执行的,但是如果是多个线程同时执行的话,是保证不了先后顺序的,因为可能先提交的后执行了。但是我们可以定义一个只有一个线程的线程池,然后依次的将T1,T2,T3提交给他执行:

public class ThreadPoolThreadExecute {public static void main(String[] args) {// 创建线程池ExecutorService executor = Executors.newSingleThreadExecutor();// 创建并启动线程T1executor.submit(new MyThread("T1"));// 创建并启动线程T2executor.submit(new MyThread("T2"));// 创建并启动线程T3executor.submit(new MyThread("T3"));// 关闭线程池executor.shutdown();}
}class MyThread implements Runnable {private String name;public MyThread(String name) {this.name = name;}@Overridepublic void run() {try {// 模拟执行任务Thread.sleep(1000);System.out.println(name + " is Running.");} catch (InterruptedException e) {e.printStackTrace();}}
}

使用CompletableFuture

Java 8引入了CompletableFuture,它是一个用于异步编程的新的强大工具。CompletableFuture提供了一系列的方法,可以用来创建、组合、转换和管理异步任务,并且可以让你实现异步流水线,在多个任务之间轻松传递结果。

如以下实现方式:

public class CompletableFutureThreadExecute {public static void main(String[] args) {// 创建CompletableFuture对象CompletableFuture<Void> future1 = CompletableFuture.runAsync(new MyThread("T1"));// 等待线程T1完成future1.join();// 创建CompletableFuture对象CompletableFuture<Void> future2 = CompletableFuture.runAsync(new MyThread("T2"));// 等待线程T2完成future2.join();// 创建CompletableFuture对象CompletableFuture<Void> future3 = CompletableFuture.runAsync(new MyThread("T3"));// 等待线程T3完成future3.join();}
}class MyThread implements Runnable {private String name;public MyThread(String name) {this.name = name;}@Overridepublic void run() {try {// 模拟执行任务Thread.sleep(1000);System.out.println(name + " is Running.");} catch (InterruptedException e) {e.printStackTrace();}}
}

上面的代码还可以做一些优化:

public class CompletableFutureThreadExecute {public static void main(String[] args) throws ExecutionException, InterruptedException {// 创建CompletableFuture对象CompletableFuture<Void> future = CompletableFuture.runAsync(new MyThread("T1")).thenRun(new MyThread("T2")).thenRun(new MyThread("T3"));future.get();}
}class MyThread implements Runnable {private String name;public MyThread(String name) {this.name = name;}@Overridepublic void run() {try {// 模拟执行任务Thread.sleep(1000);System.out.println(name + " is Running.");} catch (InterruptedException e) {e.printStackTrace();}}
}

Spring Bean的生命周期是怎么样的?

一个Spring的Bean从出生到销毁的全过程就是他的整个生命周期,那么经历以下几个阶段:
image.png

整个生命周期可以大致分为3个大的阶段,分别是:创建、使用、销毁。还可以进一步分为5个小的阶段:实例化、初始化、注册Destruction回调、Bean的正常使用以及Bean的销毁。

有人把设置属性值这一步单独拿出来了,主要是因为在源码中doCreateBean是先调了populateBean进行属性值的设置,然后再调initializeBean进行各种前置&后置处理。但是其实属性的设置其实就是初始化的一部分。要不然初始化啥呢?

有人也把注册Destruction回调放到销毁这一步了,其实是不对的,其实他不算初始化的一步,也不应该算作销毁的一个过程,他虽然和销毁有关,但是他是在创建的这个生命周期中做的。

具体到代码方面,可以参考以下这个更加详细的过程介绍,我把具体实现的代码位置列出来了。

  1. 实例化Bean
    • Spring容器首先创建Bean实例。
    • AbstractAutowireCapableBeanFactory类中的createBeanInstance方法中实现
  2. 设置属性值
    • Spring容器注入必要的属性到Bean中。
    • AbstractAutowireCapableBeanFactorypopulateBean方法中处理
  3. 检查Aware
    • 如果Bean实现了BeanNameAware、BeanClassLoaderAware等这些Aware接口,Spring容器会调用它们。
    • AbstractAutowireCapableBeanFactoryinitializeBean方法中调用
  4. 调用BeanPostProcessor的前置处理方法
    • 在Bean初始化之前,允许自定义的BeanPostProcessor对Bean实例进行处理,如修改Bean的状态。BeanPostProcessor的postProcessBeforeInitialization方法会在此时被调用。
    • AbstractAutowireCapableBeanFactoryapplyBeanPostProcessorsBeforeInitialization方法执行。
  5. 调用InitializingBean的afterPropertiesSet方法
    • 提供一个机会,在所有Bean属性设置完成后进行初始化操作。如果Bean实现了InitializingBean接口,afterPropertiesSet方法会被调用。
    • AbstractAutowireCapableBeanFactoryinvokeInitMethods方法中调用。
  6. 调用自定义init-method方法:
    • 提供一种配置方式,在XML配置中指定Bean的初始化方法。如果Bean在配置文件中定义了初始化方法,那么该方法会被调用。
    • AbstractAutowireCapableBeanFactoryinvokeInitMethods方法中调用。
  7. 调用BeanPostProcessor的后置处理方法
    • 在Bean初始化之后,再次允许BeanPostProcessor对Bean进行处理。BeanPostProcessor的postProcessAfterInitialization方法会在此时被调用。
    • AbstractAutowireCapableBeanFactoryapplyBeanPostProcessorsAfterInitialization方法执行
  8. 注册Destruction回调:
    • 如果Bean实现了DisposableBean接口或在Bean定义中指定了自定义的销毁方法,Spring容器会为这些Bean注册一个销毁回调,确保在容器关闭时能够正确地清理资源。
    • AbstractAutowireCapableBeanFactory类中的registerDisposableBeanIfNecessary方法中实现
  9. Bean准备就绪
    • 此时,Bean已完全初始化,可以开始处理应用程序的请求了。
  10. 调用DisposableBean的destroy方法
  • 当容器关闭时,如果Bean实现了DisposableBean接口,destroy方法会被调用。
  • DisposableBeanAdapterdestroy方法中实现
  1. 调用自定义的destory-method
  • 如果Bean在配置文件中定义了销毁方法,那么该方法会被调用。
  • DisposableBeanAdapterdestroy方法中实现

可以看到,整个Bean的创建的过程都依赖于AbstractAutowireCapableBeanFactory这个类,而销毁主要依赖DisposableBeanAdapter这个类。

AbstractAutowireCapableBeanFactory 的入口处,doCreateBean的核心代码如下,其中包含了实例化、设置属性值、初始化Bean以及注册销毁回调的几个核心方法。

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)throws BeanCreationException {// 实例化beanBeanWrapper instanceWrapper = null;if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}// ...Object exposedObject = bean;try {//设置属性值populateBean(beanName, mbd, instanceWrapper);if (exposedObject != null) {//初始化BeanexposedObject = initializeBean(beanName, exposedObject, mbd);}}// ...// 注册Bean的销毁回调try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}return exposedObject;}

DisposableBeanAdapter的destroy方法中核心内容如下:

@Override
public void destroy() {if (this.invokeDisposableBean) {// ...((DisposableBean) bean).destroy();}// ...}if (this.destroyMethod != null) {invokeCustomDestroyMethod(this.destroyMethod);}else if (this.destroyMethodName != null) {Method methodToCall = determineDestroyMethod();if (methodToCall != null) {invokeCustomDestroyMethod(methodToCall);}}
}

Autowired和Resource的关系?

相同点

对于下面的代码来说,如果是Spring容器的话,两个注解的功能基本是等价的,他们都可以将bean注入到对应的field中

@Autowired
private Bean beanA;
@Resource
private Bean beanB;

不同点

byName和byType匹配顺序不同

  1. Autowired在获取bean的时候,先是byType的方式,再是byName的方式。意思就是先在Spring容器中找以Bean为类型的Bean实例,如果找不到或者找到多个bean,则会通过fieldName来找。举个例子:
@Component("beanOne")
class BeanOne implements Bean {}
@Component("beanTwo")
class BeanTwo implements Bean {}
@Service
class Test {// 此时会报错,先byType找到两个bean:beanOne和beanTwo// 然后通过byName(bean)仍然没办法匹配@Autowiredprivate Bean bean; // 先byType找到两个bean,然后通过byName确认最后要注入的bean@Autowiredprivate Bean beanOne;// 先byType找到两个bean,然后通过byName确认最后要注入的bean@Autowired@Qualifier("beanOne")private Bean bean;
}
  1. Resource在获取bean的时候,和Autowired恰好相反,先是byName方式,然后再是byType方式。当然,我们也可以通过注解中的参数显示指定通过哪种方式。同样举个例子:
@Component("beanOne")
class BeanOne implements Bean {}
@Component("beanTwo")
class BeanTwo implements Bean {}
@Service
class Test {// 此时会报错,先byName,发现没有找到bean// 然后通过byType找到了两个Bean:beanOne和beanTwo,仍然没办法匹配@Resourceprivate Bean bean; // 先byName直接找到了beanOne,然后注入@Resourceprivate Bean beanOne;// 显示通过byType注入,能注入成功@Resource(type = BeanOne.class)private Bean bean;
}

作用域不同

  1. Autowired可以作用在构造器,字段,setter方法上
  2. Resource 只可以使用在field,setter方法上

支持方不同

  1. Autowired是Spring提供的自动注入注解,只有Spring容器会支持,如果做容器迁移,是需要修改代码的
  2. Resource是JDK官方提供的自动注入注解(JSR-250)。它等于说是一个标准或者约定,所有的IOC容器都会支持这个注解。假如系统容器从Spring迁移到其他IOC容器中,是不需要修改代码的。

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

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

相关文章

读取CSV中文件报ArrayIndexOutOfBounds异常

序言 有个需求要将csv文件入库&#xff0c;之前测试的文件都是可以正常解析入库的&#xff0c;但新提供的一个csv文件读取的时候捕获的异常信息就总是提示&#xff1a;Index 1 out of bounds for length 1。 读取csv文件的方法 public static List<Map<String, Object…

8.6小波变换(Wavelet Transform)边缘检测

实验原理 由于OpenCV本身并不直接支持小波变换&#xff08;Wavelet Transform&#xff09;&#xff0c;我们需要借助一些技巧来实现它。一种常见的方法是利用离散余弦变换&#xff08;DCT&#xff09;或离散傅立叶变换&#xff08;DFT&#xff09;来近似实现小波变换的功能。但…

【机器学习(六)】分类和回归任务-LightGBM算法-Sentosa_DSML社区版

文章目录 一、算法概念二、算法原理&#xff08;一&#xff09;Histogram&#xff08;二&#xff09;GOSS1、信息增益2、近似误差 &#xff08;三&#xff09;EFB 三、算法优缺点&#xff08;一&#xff09;优点&#xff08;二&#xff09;缺点 四、LightGBM分类任务实现对比&a…

AI基础 L21 Quantifying Uncertainty and Reasoning with Probabilities III

Bayesian Networks 1 Bayesian Networks • A Bayesian Network (BN) represents the dependencies among variables and encodes the full joint probability distribution concisely. • A BN is a directed graph, where each node is annotated with probability informati…

[项目][WebServer][CGI机制 设计]详细讲解

目录 1.何为CGI机制&#xff1f;2.理解CGI机制3.CGI接口设计1.ProcessNonCgi2.ProcessCgi 1.何为CGI机制&#xff1f; CGI(Common Gateway Interface)是外部应用程序(CGI程序)与WEB服务器之间的接口标准&#xff0c;是在CGI程序和WEB服务器之间传递信息的过程 2.理解CGI机制 …

[XILINX] 正点原子ZYNQ7015开发板!ZYNQ 7000系列、双核ARM、PCIe2.0、SFPX2,性能强悍,资料丰富!

正点原子ZYNQ7015开发板&#xff01;ZYNQ 7000系列、双核ARM、PCIe2.0、SFPX2&#xff0c;性能强悍&#xff0c;资料丰富&#xff01; 正点原子Z15 ZYNQ开发板&#xff0c;搭载Xilinx Zynq7000系列芯片&#xff0c;核心板主控芯片的型号是XC7Z015CLG485-2。开发板由核心板&…

JAVA开源项目 在线视频教育平台 计算机毕业设计

本文项目编号 T 027 &#xff0c;文末自助获取源码 \color{red}{T027&#xff0c;文末自助获取源码} T027&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 新…

【数据结构与算法 | 灵神题单 | 合并链表篇】力扣2, 21, 445, 2816

1. 力扣2&#xff1a;两数相加 1.1 题目&#xff1a; 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可…

o1模型:引领AI技术在STEM领域的突破与应用

o1模型是OpenAI最新推出的大型语言模型&#xff0c;它在多个领域展现出了卓越的能力&#xff0c;被认为是AI技术发展的一个重要里程碑。以下是对o1模型的详细介绍和分析&#xff1a; o1模型的简介和性能评估 o1模型在物理、化学、生物学等领域的基准任务上达到了博士生水平&…

Android Studio:驱动高效开发的全方位智能平台

目录 Android Studio 1. 智能的代码编辑与自动补全 2. 快捷键与代码模板 3. 强大的调试工具 4. 实时分析与性能优化 5. 集成的 Gradle 构建系统 6. 持续集成与自动化 7. 版本控制与团队协作 8. 丰富的插件生态与定制化 9. 快速布局与 UI 设计工具 9. 即时运行&#…

数字IC设计\FPGA 职位经典笔试面试--整理

注&#xff1a; 资料都是基于网上一些博客分享和自己学习整理而成的 1&#xff1a;什么是同步逻辑和异步逻辑&#xff1f; 同步逻辑是时钟之间有固定的因果关系。异步逻辑是各时钟之间没有固定的因果关系。 同步时序 逻辑电路的特点&#xff1a;各触发器的时钟端全部连接在一…

MySQL权限管理(DCL)总结

黑马程序员老师讲的非常好 第一个用户管理偏向于开发人员 第二个权限控制偏向于管理人员 但是怎么说呢&#xff0c;你毕竟学mysql了&#xff0c;都得学一学吧。只有精通&#xff0c;实力到位&#xff0c;才能被别人所认可&#xff01;

【打印管理】水印设置支持表单内容

09/11 主要更新模块概览 水印设置 拖动排序 恢复默认 其他更新 01 表单管理 1.1 【打印管理】-水印设置新增支持表单内容 说明&#xff1a; 在打印管理的水印设置中&#xff0c;原本仅支持企业名称作为水…

ROS笔记3.路径规划1

在 Rviz 中可视化路径规划move_base 节点的基本概念什么是Global Planner&#xff1f;什么是Global Costmap&#xff1f; 在 Rviz 中可视化路径规划 对于本章&#xff0c;您基本上需要使用 RViz 的 3 个元素&#xff1a; Map Display (Costmaps)Path Displays (Plans)2D 工具 …

加速开发体验:为 Android Studio 设置国内镜像源

Android Studio 是由 JetBrains 开发的一个官方 IDE&#xff0c;用于 Android 应用开发。由于网络原因&#xff0c;直接从 Google 的服务器下载可能会比较慢或者不稳定。幸运的是&#xff0c;我们可以通过配置国内镜像源来加速下载和更新。 文章目录 &#x1f4af; 修改 Gradle…

Go协程及并发锁应用指南

概念 协程&#xff08;Goroutine&#xff09;是Go语言独有的并发体&#xff0c;是一种轻量级的线程&#xff0c;也被称为用户态线程。相对于传统的多线程编程&#xff0c;协程的优点在于更加轻量级&#xff0c;占用系统资源更少&#xff0c;切换上下文的速度更快&#xff0c;不…

如何快速清理Docker中的停止容器?

如何快速清理Docker中的停止容器? 方法一:使用`docker container prune`方法二:结合`docker ps`和`docker rm`注意(这些命令慎用,确定容器不需要之后再执行)💖The Begin💖点点关注,收藏不迷路💖 Docker容器在停止后可能会占用不必要的磁盘空间。如何清理这些停止的…

linux 双网卡服务器突然断电后网卡单通故障解决

某台linux 双网卡服务器突然断电后网卡单通故障解决 故障现象&#xff1a;断电后重启服务器&#xff0c;主用网卡IP只能同网段访问&#xff0c;其他网段无法访问&#xff0c;备用网卡则正常&#xff1b; 解决方案&#xff1a;route -n查询路由信息&#xff0c;发现主网卡路由…

el-table的树形结构结合多选框使用,实现单选父子联动,全选,反选功能

<template><div><el-table:data"tableData":row-key"rowKey":default-expand-all"defaultExpandAll":tree-props"treeProps"><!-- 开启树形多选 --><el-table-column v-if"showSelection" width…

【视频教程】基于python深度学习遥感影像地物分类与目标识别、分割实践技术应用

我国高分辨率对地观测系统重大专项已全面启动&#xff0c;高空间、高光谱、高时间分辨率和宽地面覆盖于一体的全球天空地一体化立体对地观测网逐步形成&#xff0c;将成为保障国家安全的基础性和战略性资源。未来10年全球每天获取的观测数据将超过10PB&#xff0c;遥感大数据时…