当前位置: 首页 > article >正文

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析

    • 一、多线程基础概念
      • 1.1 什么是线程
      • 1.2 多线程的优势
      • 1.3 Java多线程模型
    • 二、Thread类的基本结构与构造函数
      • 2.1 Thread类的继承关系
      • 2.2 构造函数
    • 三、创建和启动线程
      • 3.1 继承Thread类创建线程
      • 3.2 实现Runnable接口创建线程
    • 四、Thread类的核心方法
      • 4.1 start()方法
      • 4.2 run()方法
      • 4.3 join()方法
      • 4.4 sleep(long millis)方法
      • 4.5 yield()方法
      • 4.6 setPriority(int priority)和getPriority()方法
    • 五、线程的生命周期
      • 5.1 新建状态(New)
      • 5.2 就绪状态(Runnable)
      • 5.3 运行状态(Running)
      • 5.4 阻塞状态(Blocked)
      • 5.5 死亡状态(Terminated)
    • 六、线程同步与互斥
      • 6.1 线程安全问题
      • 6.2 synchronized关键字
      • 6.3 Lock接口
    • 七、Thread类的高级特性
      • 7.1 守护线程(Daemon Thread)
      • 7.2 线程组(Thread Group)
    • 八、实战案例
      • 8.1 多线程文件读取
      • 8.2 多线程爬虫
    • 九、注意事项与常见问题
      • 9.1 避免死锁
      • 9.2 正确处理InterruptedException
      • 9.3 线程资源管理

多线程技术是提升程序性能和响应能力的重要手段,Java提供了强大且灵活的多线程支持,其中Thread类作为Java多线程编程的基础,提供了创建、管理和控制线程的核心功能。本文我将深入探讨Thread类的原理、使用方法、高级特性以及实战应用,带你全面掌握Java多线程编程的核心技术。

一、多线程基础概念

1.1 什么是线程

线程(Thread)是进程中的一个执行单元,是程序执行的最小单位。一个进程可以包含多个线程,这些线程共享进程的资源(如内存、文件句柄等),并可以并发执行。与进程相比,线程的创建和销毁开销更小,因此在提高程序效率和资源利用率方面具有显著优势。

1.2 多线程的优势

  • 提高程序响应性:在图形界面程序中,多线程可以让界面线程与工作线程分离,避免界面卡顿。
  • 提升执行效率:利用多核CPU资源,多个线程可以并行执行,加快任务处理速度。
  • 资源共享:同一进程内的线程共享资源,减少了资源分配和回收的开销。

1.3 Java多线程模型

Java通过java.lang.Thread类和java.lang.Runnable接口支持多线程编程。Thread类是线程的核心类,而Runnable接口则提供了一种更灵活的方式来定义线程任务。

二、Thread类的基本结构与构造函数

2.1 Thread类的继承关系

java.lang.Object
↳ java.lang.Thread

Thread类继承自Object类,并实现了Runnable接口,这使得Thread类既可以作为线程对象使用,也可以作为线程任务的载体。

2.2 构造函数

Thread类提供了多个构造函数,常用的有以下几种:

  1. Thread():创建一个新的线程对象,但未指定线程任务。
Thread thread = new Thread();
  1. Thread(Runnable target):创建一个新的线程对象,并将Runnable实现类作为线程任务。
Runnable task = () -> System.out.println("线程任务执行中");
Thread thread = new Thread(task);
  1. Thread(String name):创建一个指定名称的线程对象。
Thread namedThread = new Thread("MyThread");
  1. Thread(Runnable target, String name):创建一个指定名称且包含线程任务的线程对象。
Runnable task = () -> System.out.println("命名线程任务执行中");
Thread namedTaskThread = new Thread(task, "TaskThread");

三、创建和启动线程

3.1 继承Thread类创建线程

通过继承Thread类并重写其run()方法来定义线程任务:

class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("MyThread执行: " + i);}}
}public class ThreadExample {public static void main(String[] args) {MyThread thread = new MyThread();thread.start();  // 启动线程}
}

注意:启动线程需调用start()方法,而不是直接调用run()方法。直接调用run()方法相当于普通的方法调用,不会开启新线程。

3.2 实现Runnable接口创建线程

实现Runnable接口并将其作为参数传递给Thread类的构造函数:

class MyRunnable implements Runnable {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("MyRunnable执行: " + i);}}
}public class RunnableExample {public static void main(String[] args) {MyRunnable runnable = new MyRunnable();Thread thread = new Thread(runnable);thread.start();}
}

对比分析

  • 继承Thread类:代码简单直观,但由于Java单继承限制,扩展性较差。
  • 实现Runnable接口:更灵活,可实现多个接口,便于资源共享,推荐使用。

四、Thread类的核心方法

4.1 start()方法

start()方法用于启动线程,使线程进入就绪状态。JVM会为该线程分配资源,并在合适的时机执行其run()方法。一个线程只能调用一次start()方法,重复调用会抛出IllegalThreadStateException

4.2 run()方法

run()方法定义了线程的具体任务逻辑。如果继承Thread类,需要重写该方法;如果通过Runnable接口创建线程,run()方法的实现逻辑在Runnable的实现类中。

4.3 join()方法

join()方法用于让当前线程等待指定线程执行完毕。例如:

public class JoinExample {public static void main(String[] args) {Thread thread = new Thread(() -> {try {Thread.sleep(2000);  // 模拟线程执行耗时任务} catch (InterruptedException e) {e.printStackTrace();}System.out.println("子线程执行完毕");});thread.start();try {thread.join();  // 主线程等待子线程执行完毕System.out.println("子线程已结束,主线程继续执行");} catch (InterruptedException e) {e.printStackTrace();}}
}

4.4 sleep(long millis)方法

sleep()方法使当前线程暂停执行指定的毫秒数,线程进入阻塞状态。该方法会抛出InterruptedException异常,需要进行异常处理。

public class SleepExample {public static void main(String[] args) {Thread thread = new Thread(() -> {for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);  // 每隔1秒执行一次System.out.println("线程执行: " + i);} catch (InterruptedException e) {e.printStackTrace();}}});thread.start();}
}

4.5 yield()方法

yield()方法使当前线程主动让出CPU资源,进入就绪状态,允许其他具有相同优先级的线程执行。但该方法并不能保证一定会切换到其他线程。

4.6 setPriority(int priority)和getPriority()方法

setPriority()方法用于设置线程的优先级,范围为Thread.MIN_PRIORITY(1)到Thread.MAX_PRIORITY(10),默认优先级为Thread.NORM_PRIORITY(5)。getPriority()方法用于获取线程的当前优先级。

Thread thread = new Thread(() -> {// 线程任务
});
thread.setPriority(Thread.MAX_PRIORITY);  // 设置最高优先级
int priority = thread.getPriority();  // 获取优先级

五、线程的生命周期

5.1 新建状态(New)

当使用new关键字创建一个Thread对象时,线程处于新建状态,此时线程尚未启动。

5.2 就绪状态(Runnable)

调用start()方法后,线程进入就绪状态,等待JVM调度执行。处于就绪状态的线程可能在CPU上运行,也可能在等待CPU资源。

5.3 运行状态(Running)

当线程被JVM选中并分配CPU资源时,线程进入运行状态,执行run()方法中的代码。

5.4 阻塞状态(Blocked)

线程因某些原因(如调用sleep()join()方法,等待锁等)暂停执行,进入阻塞状态。阻塞状态的线程不会占用CPU资源。

5.5 死亡状态(Terminated)

当线程的run()方法执行完毕,或者因异常终止时,线程进入死亡状态,此时线程无法再被启动。

六、线程同步与互斥

6.1 线程安全问题

多线程环境下,如果多个线程同时访问共享资源,可能会导致数据不一致等线程安全问题。例如,多个线程同时对一个计数器进行自增操作,可能会出现结果错误。

6.2 synchronized关键字

synchronized关键字用于实现线程同步,保证同一时刻只有一个线程可以访问被synchronized修饰的代码块或方法。

class Counter {private int count = 0;public synchronized void increment() {count++;}public int getCount() {return count;}
}public class SynchronizedExample {public static void main(String[] args) {Counter counter = new Counter();Thread thread1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {counter.increment();}});Thread thread2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {counter.increment();}});thread1.start();thread2.start();try {thread1.join();thread2.join();System.out.println("最终计数: " + counter.getCount());} catch (InterruptedException e) {e.printStackTrace();}}
}

6.3 Lock接口

java.util.concurrent.locks.Lock接口提供了比synchronized更灵活的锁机制,如可重入锁(ReentrantLock)、读写锁(ReadWriteLock)等。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;class LockExample {private int count = 0;private Lock lock = new ReentrantLock();public void increment() {lock.lock();try {count++;} finally {lock.unlock();}}public int getCount() {return count;}
}

七、Thread类的高级特性

7.1 守护线程(Daemon Thread)

守护线程是一种特殊的线程,用于为其他线程提供服务。当所有非守护线程结束时,JVM会自动终止所有守护线程。通过setDaemon(true)方法可以将线程设置为守护线程,且必须在start()方法之前调用。

public class DaemonThreadExample {public static void main(String[] args) {Thread daemonThread = new Thread(() -> {while (true) {System.out.println("守护线程运行中...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});daemonThread.setDaemon(true);  // 设置为守护线程daemonThread.start();try {Thread.sleep(3000);  // 主线程执行3秒后结束} catch (InterruptedException e) {e.printStackTrace();}System.out.println("主线程结束");}
}

7.2 线程组(Thread Group)

线程组用于管理一组线程,可以统一设置线程的优先级、守护状态等属性,还可以批量中断线程组内的所有线程。

public class ThreadGroupExample {public static void main(String[] args) {ThreadGroup group = new ThreadGroup("MyGroup");Thread thread1 = new Thread(group, () -> {try {Thread.sleep(2000);System.out.println("线程1执行完毕");} catch (InterruptedException e) {System.out.println("线程1被中断");}});Thread thread2 = new Thread(group, () -> {try {Thread.sleep(3000);System.out.println("线程2执行完毕");} catch (InterruptedException e) {System.out.println("线程2被中断");}});thread1.start();thread2.start();group.interrupt();  // 中断线程组内的所有线程}
}

八、实战案例

8.1 多线程文件读取

使用多线程同时读取多个文件,提高读取效率:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;class FileReaderThread extends Thread {private String filePath;public FileReaderThread(String filePath) {this.filePath = filePath;}@Overridepublic void run() {try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {String line;while ((line = reader.readLine()) != null) {System.out.println(filePath + ": " + line);}} catch (IOException e) {e.printStackTrace();}}
}public class MultiThreadFileRead {public static void main(String[] args) {String[] filePaths = {"file1.txt", "file2.txt", "file3.txt"};for (String filePath : filePaths) {FileReaderThread thread = new FileReaderThread(filePath);thread.start();}}
}

8.2 多线程爬虫

利用多线程同时抓取多个网页数据:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;class CrawlerThread extends Thread {private String url;public CrawlerThread(String url) {this.url = url;}@Overridepublic void run() {try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(url).openStream()))) {String line;while ((line = reader.readLine()) != null) {System.out.println(url + ": " + line);}} catch (IOException e) {e.printStackTrace();}}
}public class MultiThreadCrawler {public static void main(String[] args) {String[] urls = {"https://example.com", "https://google.com", "https://baidu.com"};for (String url : urls) {CrawlerThread thread = new CrawlerThread(url);thread.start();}}
}

九、注意事项与常见问题

9.1 避免死锁

死锁是多线程编程中的常见问题,通常发生在多个线程互相等待对方释放锁的情况下。为避免死锁,应:

  • 尽量减少锁的使用范围
  • 按固定顺序获取锁
  • 设置合理的超时时间

9.2 正确处理InterruptedException

当线程被中断时,sleep()join()等方法会抛出InterruptedException,应正确处理该异常,避免线程异常终止。

9.3 线程资源管理

合理控制线程数量,避免创建过多线程导致资源耗尽。可以使用线程池(ExecutorService)来管理线程资源。

若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ

相关文章:

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...