java多线程使用教程

2023-11-18

如何使用多线程

在Java中,创建多线程的方式有两种:一种是继承Thread类,另一种是实现Runnable接口。以下是两种方式的详细介绍和代码示例:

继承Thread类

创建一个多线程,可以继承Thread类并重写它的run()方法。run()方法是线程的主体,当线程启动后,它的run()方法会被调用,并且该方法的执行过程中,线程将处于“运行”状态。

下面是一个简单的继承Thread类的多线程示例:

public class MyThread extends Thread {
    public void run() {
        // 线程的主体,可以在这里编写需要执行的代码
    }
}

使用这个类创建一个新线程非常简单,只需要实例化该类并调用它的start()方法即可。start()方法会启动线程并调用run()方法。

MyThread myThread = new MyThread();
myThread.start();

实现Runnable接口

Java中还提供了一种创建多线程的方式,即实现Runnable接口。实现Runnable接口的类需要实现run()方法,该方法的代码将被线程执行。

下面是一个实现Runnable接口的多线程示例:

public class MyRunnable implements Runnable {
    public void run() {
        // 线程的主体,可以在这里编写需要执行的代码
    }
}

使用这个类创建一个新线程的方式和继承Thread类的方式类似,只需要实例化该类并将它作为参数传递给Thread的构造方法即可。

MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();

线程的生命周期

线程的生命周期指的是线程从创建到销毁的整个过程。Java线程的生命周期可以分为以下5个阶段:

新建状态(New):当一个线程被创建时,它处于新建状态。此时线程还没有开始执行,也还没有分配到系统资源。

就绪状态(Runnable):当线程调用start()方法后,线程处于就绪状态。此时线程已经分配到了系统资源,等待系统调度它的时候开始执行。

运行状态(Running):当线程被系统调度执行时,线程处于运行状态。此时线程正在执行run()方法中的代码。

阻塞状态(Blocked):线程在执行过程中,可能会因为某些原因需要暂停执行,此时线程处于阻塞状态。比如,线程被sleep()、wait()、join()等方法调用时,线程将进入阻塞状态。

终止状态(Terminated):线程执行完了run()方法中的代码,或者因为异常而中断了线程,此时线程将进入终止状态。终止状态的线程不再执行任何代码。

下面是一个简单的演示线程生命周期的示例:

public class MyThread extends Thread {
    public void run() {
        System.out.println("线程处于新建状态");
        try {
            Thread.sleep(1000);
            System.out.println("线程处于就绪状态");
            Thread.sleep(1000);
            System.out.println("线程处于运行状态");
            Thread.sleep(1000);
            System.out.println("线程处于阻塞状态");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,线程将会依次进入新建状态、就绪状态、运行状态和阻塞状态。运行这个线程的代码如下:

MyThread myThread = new MyThread();
myThread.start();

线程同步

在多线程程序中,由于多个线程共享同一份资源,可能会发生冲突问题,比如多个线程同时对同一变量进行写操作,这时就需要使用同步机制来保证线程安全。

Java提供了两种同步机制:synchronized关键字和Lock接口。synchronized关键字是Java中最常用的同步机制,它可以用来修饰方法或代码块。当一个方法或代码块被synchronized修饰后,只有一个线程能够执行该方法或代码块。

下面是一个使用synchronized关键字实现线程同步的示例:

public class MyThread implements Runnable {
    private int count = 0;

    public synchronized void increase() {
        count++;
    }

    public void run() {
        for (int i = 0; i < 100000; i++) {
            increase();
        }
    }
}

在这个示例中,increase()方法被synchronized关键字修饰,当一个线程执行increase()方法时,其他线程必须等待,直到当前线程执行完毕才能执行该方法。

下面是一个使用Lock接口实现线程同步的示例:

public class MyThread implements Runnable {
    private int count = 0;
    private Lock lock = new ReentrantLock();

    public void increase() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public void run() {
        for (int i = 0; i < 100000; i++) {
            increase();
        }
    }
}

在这个示例中,increase()方法使用了Lock接口来实现线程同步,当一个线程获取了锁后,其他线程必须等待,直到当前线程释放锁才能获取锁执行该方法。

线程间通信

多个线程之间需要进行通信时,可以使用wait()、notify()和notifyAll()方法来实现。

wait()方法会使当前线程进入等待状态,直到其他线程调用notify()或notifyAll()方法唤醒该线程。notify()方法会随机唤醒一个处于等待状态的线程,而notifyAll()方法会唤醒所有处于等待状态的线程。

下面是一个使用wait()和notify()方法实现线程间通信的示例:

public class MyThread implements Runnable {
    private boolean ready = false;

    public synchronized void waitForReady() throws InterruptedException {
        while (!ready) {
            wait();
        }
    }

    public synchronized void setReady() {
        ready = true;
        notify();
    }

    public void run() {
        try {
            waitForReady();
            System.out.println("Thread is ready.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,waitForReady()方法会使当前线程进入等待状态,直到其他线程调用setReady()方法将ready标志设置为true并调用notify()方法唤醒该线程。
运行这个线程的代码如下:

MyThread myThread = new MyThread();
new Thread(myThread).start();
Thread.sleep(1000);
myThread.setReady();

在这个代码中,启动了一个线程并休眠1秒钟,然后调用setReady()方法将ready标志设置为true并调用notify()方法唤醒该线程。

线程池
线程池是一种重用线程的机制,它可以避免线程的频繁创建和销毁,提高了线程的利用率和效率。

Java提供了Executor框架来实现线程池。Executor框架提供了一些接口,如Executor、ExecutorService、ScheduledExecutorService等,可以用来创建线程池。

下面是一个使用Executor框架实现线程池的示例:

public class MyThread implements Runnable {
    private int taskId;

    public MyThread(int taskId) {
        this.taskId = taskId;
    }

    public void run() {
        System.out.println("Task " + taskId + " is running.");
        }

public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    for (int i = 1; i <= 10; i++) {
        executorService.submit(new MyThread(i));
    }
    executorService.shutdown();
}
}

在这个示例中,创建了一个包含3个线程的线程池,然后提交了10个任务给线程池执行。最后调用shutdown()方法关闭线程池。

shutdown()方法的重要性

shutdown() 方法通常在程序或系统的关闭过程中被调用,它的主要目的是进行资源释放和清理工作。在合适的时机调用 shutdown() 方法可以确保程序能够正常地关闭并释放相关资源,同时提供一种优雅的关闭方式。

以下是 shutdown() 方法的几个重要性:

  1. 资源释放:shutdown() 方法用于释放程序中使用的资源,如数据库连接、文件句柄、网络连接等。这些资源的释放对于系统的正常运行和资源管理是至关重要的,特别是在长时间运行的程序或服务中。

  2. 数据完整性:shutdown() 方法可以用来确保数据的完整性。在程序关闭前,可以通过调用 shutdown() 方法来完成未保存或未提交的数据的保存或提交操作,以避免数据丢失或不一致的情况发生。

  3. 状态保存:shutdown() 方法可以用来保存程序的状态。在程序关闭前,可以将当前的状态保存到持久化存储介质(如数据库、文件)中,以便在下次启动时能够恢复到之前的状态。

  4. 优雅关闭:通过调用 shutdown() 方法,程序可以进行一系列的清理工作,包括关闭线程、停止任务、发送终止信号等。这样可以确保程序在关闭过程中不会留下无效的线程或任务,并提供一种优雅的关闭方式,避免突然中断程序造成的数据丢失、死锁等问题。

总之,shutdown() 方法的重要性在于保证程序能够正常关闭并释放相关资源,以及提供一种优雅和可控的关闭方式。合理地使用 shutdown() 方法可以提高程序的稳定性和可靠性,确保系统能够平稳地退出或重新启动。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java多线程使用教程 的相关文章

  • 非易失性领域的出版与阅读

    public class Factory private Singleton instance public Singleton getInstance Singleton res instance if res null synchron
  • OQL 包中的所有实例

    是否有可能在OQL检索属于一个包的所有对象 或者我可以查询wildcards 正如 haridsv 建议我尝试过的 SELECT from com example and SELECT a from com example but in V
  • 使用 Exec Maven 插件分叉 Java,而不使用“exec”目标

    来自文档 https www mojohaus org exec maven plugin exec exec在单独的进程中执行程序和Java程序 exec java在同一虚拟机中执行 Java 程序 我想 fork 一个 java 程序
  • 有人用过 ServiceLoader 和 Guice 一起使用吗?

    我一直想通过我们的应用程序 构建系统进行更大规模的尝试 但更高的优先级不断将其推到次要地位 这似乎是加载 Guice 模块的好方法 并且避免了关于 硬编码配置 的常见抱怨 单个配置属性很少会自行更改 但您几乎总是会有一组配置文件 通常用于不
  • Java中Gson、JsonElement、String比较

    好吧 我想知道这可能非常简单和愚蠢 但在与这种情况作斗争一段时间后 我不知道发生了什么 我正在使用 Gson 来处理一些 JSON 元素 在我的代码中的某个位置 我将 JsonObject 的 JsonElements 之一作为字符串获取
  • java中如何知道一条sql语句是否执行了?

    我想知道这个删除语句是否真的删除了一些东西 下面的代码总是执行 else 是否删除了某些内容 执行此操作的正确方法是什么 public Deleter String pname String pword try PreparedStatem
  • getCurrentSession 在网络中休眠

    我正在使用 hibernate 和 jsp servlet 编写一个基于 Web 的应用程序 我读过有关sessionFactory getCurrentSession and sessionFactory openSession方法 我知
  • 将类转换为 JSONObject

    我有好几堂这样的课 我想将类转换为 JSONObject 格式 import java io Serializable import com google gson annotations SerializedName public cla
  • JAXB - 忽略元素

    有什么方法可以忽略 Jaxb 解析中的元素吗 我有一个很大的 XML 文件 如果我可以忽略其中一个大而复杂的元素 那么它的解析速度可能会快很多 如果它根本无法验证元素内容并解析文档的其余部分 即使该元素不正确 那就更好了 例如 这应该只生成
  • 2^31 次方的 Java 指数错误 [重复]

    这个问题在这里已经有答案了 我正在编写一个java程序来输出2的指数幂 顺便说一句 我不能使用Math pow 但是在 2 31 和 2 32 处我得到了其他东西 另外 我不打算接受负整数 My code class PrintPowers
  • 为什么解析这个 JSON 会抛出错误?

    我正在尝试解析这个 JSONObject query yahoo count 1 results rate Name USD INR id USDINR Time 12 19pm Date 10 31 2015 Bid 65 405 Ask
  • 如何使用双重调度来分析图形基元的交集?

    我正在分析图形基元 矩形 直线 圆形等 的交互并计算重叠 相对方向 合并等 这被引用为双重调度的一个主要示例 例如维基百科 http en wikipedia org wiki Double dispatch 自适应碰撞算法通常要求 不同的
  • Java 8 Stream,获取头部和尾部

    Java 8 引入了Stream http download java net jdk8 docs api java util stream Stream html类似于 Scala 的类Stream http www scala lang
  • Tomcat 6 未从 WEB-INF/lib 加载 jar

    我正在尝试找出我的 tomcat 环境中的配置问题 我们的生产服务器正在运行 tomcat 安装并从共享 NFS 挂载读取战争 然而 当我尝试使用独立的盒子 及其配置 进行同样的战争时 我收到下面发布的错误 有趣的是 如果我将 WEB IN
  • 我们如何使用 thymeleaf 绑定对象列表的列表

    我有一个表单 用户可以在其中添加任意数量的内容表对象这也可以包含他想要的列对象 就像在 SQL 中构建表一样 我尝试了下面的代码 但没有任何效果 并且当我尝试绑定两个列表时 表单不再出现 控制器 ModelAttribute page pu
  • 用于请求带有临时缓存的远程 Observable 的 RxJava 模式

    用例是这样的 我想暂时缓存最新发出的昂贵的Observable响应 但在它过期后 返回到昂贵的源Observable并再次缓存它 等等 一个非常基本的网络缓存场景 但我真的很难让它工作 private Observable
  • Spring Data Rest 多对多 POST

    首先 让我解释一下我的用例 这非常简单 有一个用户实体和一个服务实体 我使用 UserService 作为连接实体 连接表 在用户和服务之间建立多对多关联最初 会有一些用户集和一些服务集 用户可以在任何时间点订阅任何服务 在这种情况下 将向
  • 带 getClassLoader 和不带 getClassLoader 的 getResourceAsStream 有什么区别?

    我想知道以下两者之间的区别 MyClass class getClassLoader getResourceAsStream path to my properties and MyClass class getResourceAsStre
  • 设置 TreeSet 的大小

    有没有办法像数组一样对 Java 集合中的 TreeSet 进行大小限制 例如我们在数组中 anArray new int 10 数组具有固定长度 在创建数组时必须指定该长度 A TreeSet当您向其中添加元素时会自动增长 您无法设置其大
  • GAE 无法部署到 App Engine

    我正在尝试从 Eclipse 发布 Web 应用程序 我在 GAE 上创建了四个项目 可以通过登录我的帐户并查看控制台来查看它们 我已经改变了appengine web xml到项目的应用程序 ID 如果我将其更改为 GAE 上第一个创建的

随机推荐

  • 如何使用LaTeX制作PPT?

    作为LaTeX排版软件 LaTeX主要被用来制作书籍和文章 但由于现代LaTeX系统主要以PDF文件为输出方式 授课 演讲用的计算机幻灯片也日益成为LaTeX的一个重要应用 LaTeX中专门用来制作幻灯片的工具有powerdot文档类 pr
  • 探索.NET:​构建现代软件开发的核心框架

    摘要 在现代软件开发领域 选择一个合适的开发框架对于成功构建可靠 高效的应用程序至关重要 NET 读作 dot net 是一个强大而广泛使用的框架 为开发人员提供了丰富的工具和功能 以简化开发过程并加快交付时间 本文将介绍 NET的基本概念
  • 【手撕RPC服务分几步】

    手撕RPC服务分几步 前言 什么是RPC 从被调用方 provider 来说 从调用方 consumer 来说 扩展思考 dubbo架构图 前言 本文试图通过手撕RPC的理论步骤来帮助我们更好的理解其特性 也更好的理解像Dubbo sofa
  • flutter 填坑之旅(dart学习笔记篇)

    俗话说 工欲善其事必先利其器 想要撸flutter app 而不懂 dart 那就像一个不会英语的人在和英国人交流 懵 安装 dart 就不用说了 比较简单dart 官网 https dart dev 安装完成后就开启学习dart 旅程吧
  • MyEclipse配置Tomcat7

    首先我们打开Myeclipse 进入偏好设置window gt perferences 进入偏好设置 perferences 在偏好设置的搜索栏那里输入tomcat查找tomcat 如下图所示 3 我们可以看到搜索到的有四个tomcat项
  • (笔试前准备)字符串匹配算法总结

    我想说一句 我日 我讨厌KMP KMP虽然经典 但是理解起来极其复杂 好不容易理解好了 便起码来巨麻烦 老子就是今天图书馆在写了几个小时才勉强写了一个有bug的 效率不高的KMP 特别是计算next数组的部分 其实 比KMP算法速度快的算法
  • STM32 HAL库更改中断向量表的偏移地址

    以STM32F767为例 打开system stm32f7xx c文件 定位VECT TAB OFFSET 更改此宏定义的值 即可更改偏移量
  • 富维火焰识别算法

    火灾是威胁公共安全 危害人民生命财产的灾害之一 加强消防安全管理是头等大事 对火灾做到早预防 早发现 尽量避免火灾的发生尤为重要 近年来随着网络摄像机的广泛使用以及图像处理技术的不断发展 基于视频的北京富维图像火焰识别算法得到了越来越多的关
  • Android Rom修改制作工具软件集合

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 1 SIN2IMG 用于固件ftf中system sin的解包 下载地址 SIN2IMG rar 使用方法 将固件ftf文件用rar打开 解压出system sin文件 将
  • Idea 修改默认的Maven配置及修改为阿里源

    每次使用Idea创建或者导入Maven项目的时候 Idea都会使用系统默认的Maven 此时 如果我们想使用自定义安装的Maven 需要在File gt other settings gt Settings for New Projects
  • STM32-custom usb

    如何建立一个自定义的HID工程呢 下面就来讲讲 首先先介绍下工程的架构 工程的总体架构下图所示 按照下图架构建工程 分析下工程布局 首先是APP 这个组里存放着主文件mian c 管理所有中断服务程序stm3210x it c 及其管理外设
  • PageObjects支持库-Poium使用方法

    PO模式 学过自动化的都知道PageObjects模式 将页面对象封装为类 页面元素和操作封装为类的属性和方法 在测试方法中调用页面对象进行测试 关于PO模式可见 http t csdn cn 0DBlP 在PO模式下 我们一般定义个一个基
  • 想写一本书,而这是序言

    口袋书 序言 现在的风口是什么 很多人会答人工智能 Artificial Intelligence AI 人工智能是一项伟大的发明 我们不得不承认 它已经为社会带来了翻天覆地的变化 并 将在未来卷起更大的风暴 不了解人工智能 就难以在这个
  • 前端js将扁平化数据转化为=菜单树

    let menuList id 1 pid 1 name 江西 id 2 pid 1 name 南昌 id 3 pid 1 name 九江 id 4 pid 1 name 广东 id 5 pid 4 n
  • 【考研】数据结构——线索二叉树

    CSDN话题挑战赛第2期 参赛话题 学习笔记 前言 本文内容源于对 数据结构 C语言版 第2版 王道讲解学习所得心得 笔记整理和总结 本文针对线索二叉树 在最后的练习中 以举例子说明该排序方法 配以图文 讲解详细 含408真题 可搭配以下链
  • 学校与工作(献于在校大学生及入职不久的工作者)

    学校与工作 每个人都把自己眼界的局限当成世界的局限 学校是非常不同于职业工作的 有些人在其早期职业生涯中栽跟头 就是因为未能从已经生活了近20年的学校环境过渡到软件行业的美丽新世界 学生的活动具有高度约束性 工作量都是规定好了的 虽然当你是
  • IEEE-754标准浮点数,十六进制与十进制转换方法(附C代码)

    十进制数与IEEE 754 32 位转换实例讲解 https blog csdn net qq 41629142 article details 83692106 https blog csdn net a627088424 article
  • springboot集成kafka实战项目,kafka生产者、消费者、创建topic,指定消费分区

    springboot集成kafka实战项目 kafka生产者 消费者 创建topic 指定消费分区 前言 本项目代码可直接集成到你现有的springboot项目中 功能包括 1 kafka生产者配置 2 kafka消费者配置 指定分区消费
  • eigen与opencv矩阵转换,eigen与matlab函数比照

    近期 项目需要 学习使用eigen矩阵库 链接时eigen的主页 发现相关中文资料比较少 今天写下使用心得 eigen配置 windows vs系列 eigen的配置很简单 下载解压后 在VC 目录下的包含目录中 将eigen的路径包含进去
  • java多线程使用教程

    文章目录 如何使用多线程 继承Thread类 实现Runnable接口 线程的生命周期 线程同步 线程间通信 shutdown 方法的重要性 如何使用多线程 在Java中 创建多线程的方式有两种 一种是继承Thread类 另一种是实现Run