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

news2025/6/12 10:48:01

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 {
    @Override
    public 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 {
    @Override
    public 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;
    }
    
    @Override
    public 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;
    }
    
    @Override
    public 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)来管理线程资源。

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

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

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

相关文章

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

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

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#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;点…

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;随着远程办公的常态化和设备接入的爆炸式…

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;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…

均衡后的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…

零基础在实践中学习网络安全-皮卡丘靶场(第九期-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…

OPENCV形态学基础之二腐蚀

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

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…