Java零基础之多线程篇:线程控制

news2024/11/16 3:46:14

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云;欢迎大家常来逛逛

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前言

  在计算机科学中,多线程是现代操作系统和应用程序的关键概念之一。通过使用多线程,可以同时执行多个任务,提高程序的运行效率。在Java开发语言中,多线程的概念被广泛应用,并且Java提供了丰富的多线程控制机制,使得开发人员能够更好地控制线程的行为。

  本文将介绍Java多线程中的线程控制相关内容,包括线程的创建和启动、线程的睡眠和唤醒、线程的等待和通知等方面。通过掌握这些线程控制技术,我们可以更加灵活地处理多线程程序中的并发问题。

摘要

  本文将介绍Java多线程中的线程控制相关内容,包括线程的创建和启动、线程的睡眠和唤醒、线程的等待和通知等方面。通过对这些线程控制技术的讲解和实践,我们可以更好地理解和应用多线程编程。

简介

  在Java中,线程是最基本的执行单元。通过创建和启动线程,我们可以同时执行多个任务。Java提供了多种方式来创建和启动线程,包括继承Thread类、实现Runnable接口、使用线程池等。

  在多线程程序中,线程的睡眠和唤醒是非常重要的操作。线程的睡眠可以通过Thread类的sleep()方法实现,而线程的唤醒可以通过调用线程的notify()notifyAll()方法来实现。

  另外,线程的等待和通知也是多线程编程中常用的技术。线程的等待可以通过调用对象的wait()方法实现,而线程的通知可以通过调用对象的notify()notifyAll()方法来实现。

源代码解析

线程的创建和启动

  在Java中,我们可以通过继承Thread类来创建一个线程类,然后通过调用该线程类的start()方法来启动线程。下面是一个简单的示例:

package com.example.javase.ms.threadDemo.day3;

/**
 * @Author ms
 * @Date 2024-04-12 18:27
 */
public class MyRunnable implements Runnable {
    public void run() {
        // 线程执行的代码
        System.out.println("线程执行啦!");
    }
}
package com.example.javase.ms.threadDemo.day3;

/**
 * @Author ms
 * @Date 2024-04-12 18:27
 */
public class ThreadDemo {

    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();

        System.out.println("主线程执行啦!");
    }
}

  上述代码中,我们定义了一个继承自Thread类的MyThread类,并在该类中重写了run方法。在ThreadDemo 类中创建MyThread对象,并调用start()方法来启动线程。

  根据如上测试用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

线程的睡眠和唤醒

案例1:

线程的睡眠可以通过Thread类的sleep()方法实现。下面是一个示例:

package com.example.javase.ms.threadDemo.day3;

import java.time.LocalTime;

/**
 * @Author ms
 * @Date 2024-04-12 19:37
 */
public class ThreadSleepTest {
    public static void main(String[] args) {
        try {
            System.out.println("睡眠前:" + LocalTime.now());
            Thread.sleep(3000); // 线程睡眠1秒
            System.out.println("睡眠后:" + LocalTime.now());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

  上述代码中,演示了如何在Java中使用Thread.sleep()方法使当前线程暂停执行一段时间。在这个例子中,线程将暂停执行3000毫秒,也就是3秒。

代码分析
  1. 程序首先打印出睡眠前的时间,使用LocalTime.now()获取当前的本地时间(不包含日期信息)。

  2. 接着,Thread.sleep(3000)调用使当前线程进入睡眠状态,暂停执行3秒钟。在这段时间内,当前线程不会执行任何操作,并且不会占用CPU资源。

  3. 如果在sleep期间线程被中断,InterruptedException将被抛出。在catch块中处理这个异常,打印堆栈跟踪信息。

  4. 睡眠结束后,程序再次打印出睡眠后的时间。

运行结果

  当你运行这个程序时,你会看到控制台输出两次时间,第一次是程序开始睡眠前的时间,第二次是睡眠结束后的时间。两次输出的时间间隔大约是3秒,这由Thread.sleep(3000)指定。

  根据如上测试用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

注意事项
  • Thread.sleep()方法接受的参数是毫秒数,即睡眠的时间长度。
  • InterruptedException是一个检查型异常,必须显式处理(try-catch)或声明抛出(throws)。
  • 在多线程程序中,sleep()方法是一种简单的线程调度机制,但不是最精确或最可靠的方法。例如,线程可能会比预期的睡眠时间稍微长一些才被唤醒,这取决于操作系统的线程调度策略。
  • 为了避免在睡眠期间占用CPU资源,可以在调用sleep()之前将线程的状态设置为Thread.State.WAITING

这个简单的例子展示了Thread.sleep()方法的基本用法,它是Java多线程编程中常用的工具之一。在实际应用中,sleep()方法可以用来实现线程的延迟执行、时间间隔控制等。

案例2:

  线程的唤醒可以通过调用线程的notify()notifyAll()方法来实现。下面是一个示例:

package com.example.javase.ms.threadDemo.day3;

/**
 * @Author ms
 * @Date 2024-04-12 19:42
 */
public class MyThread_wait extends Thread {
    private boolean running = false;

    public void run() {
        synchronized (this) {
            while (!running) {
                try {
                    wait(); // 线程等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public synchronized void wakeup() {
        running = true;
        notify(); // 唤醒线程
    }

    public static void main(String[] args) {
        MyThread_wait thread = new MyThread_wait();
        thread.start();
        thread.wakeup();
    }
}

  对于这段代码,我是展示了一个使用wait()notify()方法来实现线程间的协作的简单示例。在这个例子中,有一个MyThread_wait类,它继承自Thread类,并实现了一个简单的启动-通知模式。

代码分析
  1. MyThread_wait类中定义了一个布尔字段running,用来控制线程的执行状态。

  2. run()方法中,线程进入一个while循环,检查running变量的状态。如果runningfalse,则线程调用wait()方法进入等待状态。

  3. wait()方法会导致线程在没有其他线程调用notify()notifyAll()方法之前一直等待。当线程被唤醒时,它会跳过wait()调用后面的代码,直接继续执行循环。

  4. wakeup()方法用来设置runningtrue,并通过调用notify()唤醒在此对象监视器上等待的单个线程。如果有多个线程在等待,notify()方法会选择其中一个线程进行唤醒。

  5. main方法中,创建了MyThread_wait的一个实例,并启动了线程。然后立即调用wakeup()方法来唤醒正在等待的线程。

运行结果

  当程序运行时,MyThread_wait线程开始执行,但由于running变量初始为false,它会在run()方法中调用wait()并进入等待状态。随后,main方法中的wakeup()调用会唤醒等待的线程。线程被唤醒后,running变量被设置为true,线程将继续执行run()方法中的剩余代码。

  根据如上测试用例,这里我们本地执行一下,结果展示如下:

在这里插入图片描述

注意事项
  • wait()方法必须在synchronized块或方法中调用,否则会抛出IllegalMonitorStateException异常。
  • wait()方法会导致当前线程释放对象的锁,并进入等待池等待其他线程的notify()notifyAll()调用。
  • notify()方法会随机选择一个在对象监视器上等待的线程进行唤醒,而notifyAll()会唤醒所有等待的线程。
  • 在使用wait()notify()进行线程协作时,要特别注意避免死锁和活锁的情况。

  这个示例演示了线程间的基本协作机制,是多线程编程中的一个常见模式。通过这种方式,线程可以根据条件等待或发出通知,以实现更复杂的并发控制逻辑。

线程的等待和通知

  线程的等待可以通过调用对象的wait方法实现。下面是一个示例:

/**
 * @Author ms
 * @Date 2024-04-12 19:42
 */
public class MyThread extends Thread {
    public void run() {
        synchronized (this) {
            try {
                wait(); // 线程等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
        synchronized (thread) {
            thread.notify(); // 唤醒线程
        }
    }
}

  上述代码中,我们在MyThread类的run()方法中使用synchronized关键字来实现线程的同步,然后调用wait方法使线程等待。在Main类中创建MyThread对象,并使用synchronized关键字来实现线程的同步,然后调用notify方法来唤醒线程。

应用场景案例

  Java多线程的线程控制技术可以应用于各种场景,下面是一个简单的案例:

  假设我们有一个多线程程序,其中有一个线程负责读取网络数据,另一个线程负责处理网络数据。我们希望当读取线程读取到数据后,通知处理线程进行处理。

  我们可以使用线程的等待和通知技术来实现这个功能。在读取线程中,可以使用wait方法使线程等待,而在处理线程中,可以使用notify方法来唤醒线程。

/**
 * @Author ms
 * @Date 2024-04-12 19:42
 */
public class ReadThread extends Thread {
    public void run() {
        // 读取网络数据
        // ...

        synchronized (this) {
            notify(); // 唤醒处理线程
        }
    }
}

public class ProcessThread extends Thread {
    public void run() {
        synchronized (readThread) {
            try {
                readThread.wait(); // 线程等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 处理网络数据
        // ...
    }

    private ReadThread readThread; // 读取线程

    public ProcessThread(ReadThread readThread) {
        this.readThread = readThread;
    }
}

public class Main {
    public static void main(String[] args) {
        ReadThread readThread = new ReadThread();
        ProcessThread processThread = new ProcessThread(readThread);

        readThread.start();
        processThread.start();
    }
}

  上述代码中,我们定义了一个ReadThread类和一个ProcessThread类,分别用于读取网络数据和处理网络数据。在Main类中创建ReadThread对象和ProcessThread对象,并通过构造函数将它们关联起来。

优缺点分析

  Java多线程的线程控制技术有以下优点:

  • 提高程序的运行效率:通过多线程可以同时执行多个任务,提高程序的并发性和响应性。
  • 灵活性高:Java提供了多种多线程控制技术,开发人员可以根据实际需求选择合适的技术。
  • 方便调试和测试:通过合理使用线程控制技术,可以更好地控制线程的执行顺序和时间,方便调试和测试。

  但是,Java多线程的线程控制技术也存在一些缺点:

  • 复杂性较高:线程控制涉及到线程的创建、启动、睡眠和唤醒、等待和通知等多个方面,对开发人员的编程能力要求较高。
  • 容易出错:线程控制涉及到多线程并发执行,存在线程安全和竞争条件等问题,容易出现错误。

类代码方法介绍

Thread类

  • start():启动线程,使线
  • start():启动线程,使线程开始执行run()方法中的代码。
  • run():定义线程执行的任务,必须在run()方法中编写线程要执行的代码。
  • sleep(long millis):使当前线程暂停执行指定的时间(毫秒),并让出CPU给其他线程。
  • interrupt():请求中断一个线程,线程可以检查自身的中断状态,并根据需要自行处理中断。
  • isAlive():测试线程是否在活动状态,即线程已经开始且尚未完成。
  • join():使当前线程等待,直到另一个线程完成执行。
  • notify():唤醒在此对象监视器上等待的单个线程。
  • notifyAll():唤醒在此对象监视器上等待的所有线程。

Object类(所有类都继承自Object)

  • wait():使当前线程等待,直到另一个线程调用此对象的notify()notifyAll()方法。
  • notify():唤醒在此对象监视器上等待的单个线程。
  • notifyAll():唤醒在此对象监视器上等待的所有线程。

全文小结

  本文详细介绍了Java多线程中的线程控制技术,包括线程的创建和启动、线程的睡眠和唤醒、线程的等待和通知等。通过这些技术,我们可以创建和管理多个线程,使得程序能够并行执行多个任务,从而提高程序的运行效率和响应性。

  同时,我们也讨论了多线程编程的优点和缺点,以及如何使用Java提供的Thread类和Object类中的方法来控制线程的行为。掌握了这些知识,Java开发人员可以更加灵活和高效地处理多线程程序中的并发问题。

总结

  多线程是Java编程中的一个重要特性,它为我们提供了强大的并发处理能力。通过合理地使用线程控制技术,我们可以使程序更加高效和响应迅速。然而,多线程编程也带来了复杂性和潜在的错误,如线程安全问题和竞争条件。因此,开发人员需要仔细设计和测试多线程程序,确保程序的正确性和稳定性。

  在实际开发中,除了本文介绍的基础知识,还有许多高级的并发工具和框架,如java.util.concurrent包中的类,可以帮助我们更好地处理并发问题。不断学习和实践,深入理解多线程和并发编程的原理和技巧,对于成为一名优秀的Java开发人员至关重要。

… …

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

… …

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。

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

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

相关文章

RISC-V竞赛|第二届 RISC-V 软件移植及优化锦标赛报名正式开始!

目录 赛事背景 赛道方向 适配夺旗赛 优化竞速赛 比赛赛题(总奖金池8万元!) 🔥竞速赛 - OceanBase 移植与优化 比赛赛程(暂定) 赛事说明 「赛事背景」 为了推动 RISC-V 软件生态更快地发展&#xff0…

健身动作AI识别,仰卧起坐计数(含UI界面)

用Python和Mediapipe打造,让你的运动效果一目了然! 【技术揭秘】 利用Mediapipe的人体姿态估计,实时捕捉关键点,精确识别动作。 每一帧的关键点坐标和角度都被详细记录,为动作分析提供数据支持。 支持自定义动作训练&a…

Jave-this关键字

目录 1.this关键字 先看一段代码,并分析问题 什么是this 案例演示 2.this的注意事项和使用细节 1.this关键字 先看一段代码,并分析问题 什么是this this就 代表的是当前对象。 this可以大概理解成“我的” ,比如我的书包,这…

基于Java中的SSM框架实现大创项目申报管理系统项目【项目源码+论文说明】计算机毕业设计

基于Java中的SSM框架实现大创项目申报管理系统演示 摘要 经济的高速发展进一步推动了种类繁多的项目落地,传统的项目在申报过程中主要通过纸质文件的方式实现申报信息的传递,同时不同的项目内容所对应的申报资料模板也有所差异,人工整理的提…

没有显卡,怎么玩AI绘图?

或许很多人跟我一样,没有显卡,但又很想玩AI绘图,但本地绘图怕是无缘了,只能借助云GPU的方式了。 今天跟大家分享一下一个简单目前可白嫖无门槛的方法实现无显卡也能玩AI绘图。 方案就是ComfyUIBizyAir云节点。 ComfyUI介绍 来…

【软考】虚拟存储器

目录 1. 说明2. 定义3. 工作原理4. 管理方式5. 优点6. 例题6.1 例题1 1. 说明 1.在概念上,可以将主存存储器看作一个由若干个字节构成的存储空间,每个字节(称为一个存储单元)有一个地址编号,主存单元的该地址称为物理地址(Physical Address)…

数值分析——三次样条插值

系列文章目录 数值分析——拉格朗日插值 数值分析——牛顿插值多项式 数值分析——埃尔米特(Hermit)插值 数值分析——分段低次插值 文章目录 系列文章目录前言一、理论推导1.三次样条函数2.三次样条插值函数的求解条件3.三次样条插值函数的建立 二、MA…

简单反射型XSS的复现

xss反射型攻击&#xff1a; 1.最简单的漏洞复现&#xff1a; 这里我们有一个最简单的网页&#xff1a;由于地址不存在&#xff0c;所以图片加载不出来。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta…

FP8量化

https://arxiv.org/html/2402.16363v5 LLama3.1用了FP8量化&#xff1a; FP8也可以用scaling factor来扩大表示范围&#xff0c;对吧&#xff1f;

开源在线剪切板 PrivateBin 安装和使用教程

我们经常需要在网上快速分享一些文本内容&#xff0c;比如代码片段、临时笔记或者敏感信息。传统的在线剪贴板服务虽然使用方便&#xff0c;但往往缺乏足够的隐私保护。 那么&#xff0c;有没有一种既方便又安全的在线文本分享方式呢&#xff1f;今天我要向大家推荐一个优秀的…

常见的图像融合方法

这里我们将介绍一些常用的图像融合方式&#xff0c;并不涉及到诸如CutMix、MixUp、TokenMix、Mosaic、Copy-Paste等图像增强方法。 首先是读取图像&#xff0c;我们这边采用了PIL库进行&#xff0c;那么读进来就应该是一个Image对象。下面介绍Image对象与array的转换方式。 f…

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测

土地利用/土地覆盖数据是生态、环境和气象等领域众多模型的重要输入参数之一。基于遥感影像解译&#xff0c;可获取历史或当前任何一个区域的土地利用/土地覆盖数据&#xff0c;用于评估区域的生态环境变化、评价重大生态工程建设成效等。借助CLUE模型&#xff0c;实现对未来土…

AI9-文本识别

本章主要介绍文本识别算法的理论知识,包括背景介绍、算法分类和部分经典论文思路。 通过本章的学习,你可以掌握: 1. 文本识别的目标 2. 文本识别算法的分类 3. 各类算法的典型思想 1 背景介绍 文本识别是OCR(Optical Character Recognition)的一个子任务,其任务为识别一个…

pytorch的入门使用

pytorch安装略&#xff01; 一.张量Tensor 张量是一个统称其中包含0阶&#xff0c;1阶&#xff0c;2阶&#xff0c;3阶&#xff0c;4阶&#xff0c;.......n阶。 0阶&#xff1a;标量&#xff0c;常数&#xff0c;0-D Tensor 1阶&#xff1a;向量&#xff0c;1-D Tensor 2…

使用java反编译工具jad

文章目录 反编译工具 JAD下载配置环境变量使用其他反编译工具 JD-GUI 反编译工具 JAD 反编译是指将编译后的字节码文件&#xff08;.class 文件&#xff09;转换回可读的 Java 源代码。JAD (Java Decompiler) 是一个经典的反编译工具&#xff0c;广泛用于将 Java 字节码反编译…

国内AI大模型168个,哪个最有前途?

168个国产大模型&#xff0c;都是什么来头&#xff1f; 1785年&#xff0c;瓦特改进了蒸汽机&#xff0c;人类从此摆脱了手工业的桎梏&#xff0c;迈向辉煌的蒸汽时代。 1870年&#xff0c;第二次工业革命光芒四溢&#xff0c;人类踏上了电气时代的漫长征程。 20世纪70年代后…

手机有两个卡槽分别放什么卡,这篇文章建议收藏!

你发现了吗&#xff0c;我们现在对于手机卡的需求是越来越大了&#xff0c;相信大多数用户手上都不止一张SIM卡&#xff0c;大部分都是双卡&#xff0c;甚至三卡了&#xff0c;那么&#xff0c;这些卡槽你真的利用对了吗&#xff1f; 这篇文章就告诉大家&#xff0c;如何更好的…

【Windows】Beyond Compare 5(文件数据对比神器) 软件介绍

今天给大家介绍的软件叫Beyond Compare&#xff0c;这是一个文件数据对比神器&#xff0c;可以让你从茫茫数据、文字中解放出来。 Beyond Compare 是一款功能强大的文件和文件夹比较工具&#xff0c;主要用于比较和同步文件、文件夹及其内容。以下是该软件的主要特点和功能&…

一款免费开源的在线白板,手绘风格在线画图神器

Excalidraw 是一款开源的虚拟手绘风格在线白板工具&#xff0c;它专注于提供简单、直观且功能丰富的绘图体验。这款工具特别适合用于创建图表、线框图、思维导图、流程图以及其他各种类型的图形和视觉内容。 Excalidraw 的主要特点包括&#xff1a; 免费开源&#xff1a;Exca…

如何正确地实现虚拟类?

在 Python 中&#xff0c;所谓的虚拟类通常是指抽象基类&#xff08;Abstract Base Class&#xff0c;简称 ABC&#xff09;。抽象基类不可实例化&#xff0c;其主要作用是定义一组抽象方法&#xff0c;子类必须实现这些抽象方法才能被实例化。 要正确实现虚拟类&#xff08;抽…