【面试精讲】Java线程6种状态和工作原理详解,Java创建线程的4种方式

Java线程6种状态和工作原理详解,Java创建线程的4种方式

目录

一、Java线程的六种状态

二、Java线程是如何工作的?

三、BLOCKED 和 WAITING 的区别

四、start() 和 run() 源码分析

五、Java创建线程的所有方式和代码详解

1. 继承Thread类

2. 实现Runnable接口

3. 实现Callable接口与FutureTask

4. 使用线程池

总结

 博主v:XiaoMing_Java


在并发编程领域,Java线程是实现多任务处理的基石。了解其状态及工作原理对于开发高效、稳定的Java应用至关重要。本文将深入探讨Java线程的各种状态以及它们的工作机制。

一、Java线程的六种状态

Java线程在其生命周期内可以处于以下几种状态:

  1. 新建(New): 线程被创建后,但在调用start()方法之前的状态。
  2. 可运行(Runnable): 线程已经启动,并且执行start()方法后的状态。在此状态,线程可能正在运行也可能正在等待CPU分配时间片,具体取决于操作系统的线程调度器。
  3. 阻塞(Blocked): 当一个线程试图获取一个对象的锁(不是通过synchronized块或方法),而该锁被其他线程持有,则该线程会进入阻塞状态。
  4. 等待(Waiting): 当一个线程等待另一个线程执行特定动作时(例如,通过Object.wait()Thread.join()LockSupport.park()),该线程会进入等待状态。
  5. 超时等待(Timed Waiting): 类似于等待状态,但有最大等待时间限制。当线程调用带有指定等待时间的sleep()wait()join(), 或LockSupport.parkNanos()/parkUntil()时,会处于该状态。
  6. 终止(Terminated): 线程的运行结束,无论是正常完成还是中途退出。
public enum State {/*** 新建状态,线程被创建出来,但尚未启动时的线程状态*/NEW,/*** 就绪状态,表示可以运行的线程状态,但它在排队等待来自操作系统的 CPU 资源*/RUNNABLE,/*** 阻塞等待锁的线程状态,表示正在处于阻塞状态的线程,正在等待监视器锁,比如等待执行 synchronized 代码块或者* 使用 synchronized 标记的方法*/BLOCKED,/*** 等待状态,一个处于等待状态的线程正在等待另一个线程执行某个特定的动作。* 例如,一个线程调用了 Object.wait() 它在等待另一个线程调用* Object.notify() 或 Object.notifyAll()*/WAITING,/*** 计时等待状态,和等待状态 (WAITING) 类似,只是多了超时时间,比如* 调用了有超时时间设置的方法 Object.wait(long timeout) 和 * Thread.join(long timeout) 就会进入此状态*/TIMED_WAITING,/*** 终止状态,表示线程已经执行完成*/
}

二、Java线程是如何工作的?

Java线程的工作机制与操作系统的线程管理紧密相关。Java虚拟机(JVM)通过映射到底层操作系统的原生线程实现来管理Java线程。这个过程主要包括线程的创建、调度、上下文切换、以及终止等方面。

  • 创建: 当在Java程序中创建线程对象并调用其start()方法时,JVM会向操作系统请求创建一个新的线程。操作系统为此分配资源并开始执行线程的run()方法。
  • 调度与执行: 一旦线程处于可运行状态,它就成为了操作系统调度器的候选对象。基于操作系统的策略和当前情况(如优先级、CPU亲和性等),调度器选择线程并分配CPU时间片进行执行。在任意给定时刻,单核CPU只能执行一个线程,而多核CPU可以并行执行多个线程。
  • 上下文切换: 当当前执行的线程由于时间片耗尽、等待IO操作、试图获取锁等原因需要被暂停时,操作系统保存当前线程的状态(称为“上下文”),并恢复另一个线程的上下文以继续执行。这个保存和恢复的过程称为上下文切换。
  • 等待与通知: 当线程进入等待状态时,它会释放所有持有的锁,直到其他线程通过特定的通知机制(如notify()notifyAll()方法)将其唤醒。此时,线程再次竞争获取必要的锁以继续执行。
  • 终止: 线程执行完毕后,或者因为未捕获的异常而终止,JVM会清理线程所占用的所有资源,并将线程标记为终止状态。

线程的工作模式是,首先先要创建线程并指定线程需要执行的业务方法,然后再调用线程的 start() 方法,此时线程就从 NEW(新建)状态变成了 RUNNABLE(就绪)状态,此时线程会判断要执行的方法中有没有 synchronized 同步代码块,如果有并且其他线程也在使用此锁,那么线程就会变为 BLOCKED(阻塞等待)状态,当其他线程使用完此锁之后,线程会继续执行剩余的方法。

当遇到 Object.wait() 或 Thread.join() 方法时,线程会变为 WAITING(等待状态)状态,如果是带了超时时间的等待方法,那么线程会进入 TIMED_WAITING(计时等待)状态,当有其他线程执行了 notify() 或 notifyAll() 方法之后,线程被唤醒继续执行剩余的业务方法,直到方法执行完成为止,此时整个线程的流程就执行完了,执行流程如下图所示:

三、BLOCKED 和 WAITING 的区别

虽然 BLOCKED 和 WAITING 都有等待的含义,但二者有着本质的区别,首先它们状态形成的调用方法不同,其次 BLOCKED 可以理解为当前线程还处于活跃状态,只是在阻塞等待其他线程使用完某个锁资源;而 WAITING 则是因为自身调用了 Object.wait() 或着是 Thread.join() 又或者是 LockSupport.park() 而进入等待状态,只能等待其他线程执行某个特定的动作才能被继续唤醒,比如当线程因为调用了 Object.wait() 而进入 WAITING 状态之后,则需要等待另一个线程执行 Object.notify() 或 Object.notifyAll() 才能被唤醒。

四、start() 和 run() 源码分析

首先从 Thread 源码来看,start() 方法属于 Thread 自身的方法,并且使用了 synchronized 来保证线程安全

public synchronized void start() {// 状态验证,不等于 NEW 的状态会抛出异常if (threadStatus != 0)throw new IllegalThreadStateException();// 通知线程组,此线程即将启动group.add(this);boolean started = false;try {start0();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {// 不处理任何异常,如果 start0 抛出异常,则它将被传递到调用堆栈上}}
}

run() 方法为 Runnable 的抽象方法,必须由调用类重写此方法,重写的 run() 方法其实就是此线程要执行的业务方法

public class Thread implements Runnable {// 忽略其他方法......private Runnable target;@Overridepublic void run() {if (target != null) {target.run();}}
}@FunctionalInterface
public interface Runnable {public abstract void run();
}

五、Java创建线程的所有方式和代码详解

Java提供了多种创建和管理线程的方式,从简单的Thread类继承到实现RunnableCallable接口,再到使用强大的线程池管理。

选择合适的方式取决于具体的应用场景和需求。对于简单的任务,直接使用Thread类或Runnable接口可能就足够了。而对于需要任务执行结果的情况,Callable接口将是更好的选择。

在处理大量并发任务时,利用线程池可以显著提高性能和资源利用率。了解和掌握这些方法,对于编写高效、稳定的Java多线程程序至关重要。

1. 继承Thread

Java允许通过继承Thread类的方式创建线程。这种方式简单直观,适用于简单的线程任务。

class MyThread extends Thread {@Overridepublic void run() {// 这里填写线程任务代码System.out.println("线程运行中...");}
}public class ThreadExample {public static void main(String[] args) {MyThread t = new MyThread();t.start(); // 启动新线程}
}

2. 实现Runnable接口

实现Runnable接口是创建线程最常见的方式之一,它提供了更大的灵活性,允许线程类继承其他类。

class MyRunnable implements Runnable {@Overridepublic void run() {// 线程任务System.out.println("通过Runnable接口运行线程...");}
}public class RunnableExample {public static void main(String[] args) {Thread t = new Thread(new MyRunnable());t.start(); // 启动线程}
}

3. 实现Callable接口与FutureTask

Callable接口类似于Runnable,但它可以返回执行结果,并且能抛出异常。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {// 返回执行结果return 123;}
}public class CallableExample {public static void main(String[] args) throws InterruptedException, ExecutionException {FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());Thread t = new Thread(futureTask);t.start(); // 启动线程// 获取执行结果Integer result = futureTask.get();System.out.println("Callable返回的结果: " + result);}
}

4. 使用线程池

Java的Executor框架提供了一个强大的线程池管理机制,能更高效地管理线程生命周期。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(5); // 创建固定大小的线程池for (int i = 0; i < 10; i++) {Runnable worker = new MyRunnable();executor.execute(worker);  // 提交任务给线程池执行}executor.shutdown(); // 关闭线程池while (!executor.isTerminated()) {// 等待所有任务完成}System.out.println("所有线程已完成任务");}
}

总结

理解Java线程的状态及其转换是掌握Java并发编程的关键。正确地管理线程状态,合理利用同步机制,可以有效提高Java应用的性能和响应速度。探讨Java线程的六种状态、Java线程是如何工作的,Java创建线程【继承Thread类、实现Runnable接口、实现Callable接口与FutureTask、使用线程池】的所有方式

如果本文对你有帮助 欢迎 关注 、点赞 、收藏 、评论, 博主才有动力持续记录遇到的问题!!!

 博主v:XiaoMing_Java

  📫作者简介:嗨,大家好,我是 小明(小明Java问道之路),互联网大厂后端研发专家,2022博客之星TOP3 / 博客专家 / CSDN后端内容合伙人、InfoQ(极客时间)签约作者、阿里云签约博主、全网 6 万粉丝博主。


🍅 文末获取联系 🍅  👇🏻 精彩专栏推荐订阅收藏 👇🏻

专栏系列(点击解锁)

学习路线(点击解锁)

知识定位

🔥Redis从入门到精通与实战🔥

Redis从入门到精通与实战

围绕原理源码讲解Redis面试知识点与实战

🔥MySQL从入门到精通🔥

MySQL从入门到精通

全面讲解MySQL知识与企业级MySQL实战

🔥计算机底层原理🔥

深入理解计算机系统CSAPP

以深入理解计算机系统为基石,构件计算机体系和计算机思维

Linux内核源码解析

围绕Linux内核讲解计算机底层原理与并发

🔥数据结构与企业题库精讲🔥

数据结构与企业题库精讲

结合工作经验深入浅出,适合各层次,笔试面试算法题精讲

🔥互联网架构分析与实战🔥

企业系统架构分析实践与落地

行业最前沿视角,专注于技术架构升级路线、架构实践

互联网企业防资损实践

互联网金融公司的防资损方法论、代码与实践

🔥Java全栈白宝书🔥

精通Java8与函数式编程

本专栏以实战为基础,逐步深入Java8以及未来的编程模式

深入理解JVM

详细介绍内存区域、字节码、方法底层,类加载和GC等知识

深入理解高并发编程

深入Liunx内核、汇编、C++全方位理解并发编程

Spring源码分析

Spring核心七IOC/AOP等源码分析

MyBatis源码分析

MyBatis核心源码分析

Java核心技术

只讲Java核心技术

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

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

相关文章

Node-RED在Linux二次开发网关中能源数据实时采集与优化

智能电网与分布式能源系统已成为推动绿色能源转型的重要载体。为了更好地应对多样化的能源供给与需求挑战&#xff0c;以及实现更高效的能源管理&#xff0c;Linux二次开发网关与Node-RED这一创新组合应运而生。 Linux二次开发网关作为高度定制化的硬件平台&#xff0c;其开源特…

【深入理解LRU Cache】:缓存算法的经典之作

目录 一、什么是LRU Cache&#xff1f; 二、LRU Cache的实现 1.JDK中类似LRUCahe的数据结构LinkedHashMap 2.自己实现双向链表 三、LRU Cache的OJ 一、什么是LRU Cache&#xff1f; LRU Cache&#xff08;Least Recently Used的缩写&#xff0c;即最近最少使用&#xff0…

跨平台是什么意思?——跟老吕学Python编程

跨平台是什么意思&#xff1f;——跟老吕学Python编程 跨平台跨平台释义跨平台软件数据库管理系统(DBMS)&#xff1a;网站服务器、应用程序服务器&#xff1a;网络浏览器&#xff1a; 跨平台编程语言跨平台详细解说跨平台应用前景 跨平台 计算机领域术语 跨平台概念是软件开发中…

Zookeeper详解

1.Zookeeper概述 1.Zookeeper概念 Zookeeper是 Apache Hadoop 项目下的一个子项目&#xff0c;是一个树形目录服务 Zookeeper 翻译过来就是动物园管理员&#xff0c;他是用来管 Hadoop&#xff08;大象&#xff09;、Hive(蜜蜂)、Pig(小猪)的管理员。简称zk Hadoop: 存储海…

canvas实现水印逻辑分析

目录 效果图一、相关文档二、分析三、实现1、将水印文字转为水印图片2、给刚生成的水印图片加入旋转以及间隔&#xff08;1&#xff09;旋转位移&#xff08;2&#xff09;间隔位移&#xff08;3&#xff09;最后使用toDataURL导出为png图片 3、将生成的水印图片依次排布在需要…

【Python数据结构与判断2/7】数据和判断小结

目录 序言 print() 变量 赋值 四种数据类型 字符串 格式化输出 四则运算 取整与取模 比较运算 逻辑运算 判断 if语句 if-else语句 if-elif-else语句 Tips 空值、0、非0非空值 实战案例 输入密码 短信模板 总结 序言 今天将对前面学过的内容进行一个复习小结…

科技引领品质:飞利浦智能锁“12年免费换新机”重塑行业新标杆

随着智能锁行业的竞争愈发火热&#xff0c;各大品牌在技术创新和服务升级方面不断推陈出新。售后服务的形态正发生深刻变化&#xff0c;从传统的保修维修到如今的技术支持、24小时在线客服等&#xff0c;各大品牌都在不断地提升售后服务水平&#xff0c;以创新的服务理念和先进…

配置与管理DNS服务器

配置与管理DNS服务器 **1&#xff0c;什么是DNS&#xff1f;**负责将域名转换成实际想对应的ip地址&#xff0c;这个过程交域名解析。 **2&#xff0c;域名解析的方法&#xff1a;**分布式&#xff0c;层次结构的数据库系统。根域&#xff0c;顶级域&#xff0c;二级域&#…

sql注入基础学习

1.常用SQL语句 01、显示数据库 show databases&#xff1b; 02、打开数据库 use db name&#xff1b; 03、显示数据表 show tables&#xff1b; 04、显示表结构 describe table_name&#xff1b; 05、显示表中各字段信息&#xff0c;即表结构 show columns from table_nam…

面向对象的编程语言是什么意思?——跟老吕学Python编程

面向对象的编程语言是什么意思&#xff1f;——跟老吕学Python编程 面向对象是什么意思&#xff1f;面向对象的定义面向对象的早期发展面向对象的背景1.审视问题域的视角2.抽象级别3.封装体4.可重用性 面向对象的特征面向对象的开发方法面向对象程序设计基本思想实现 面向对象的…

数据结构-稀疏数组

文章目录 1、什么是稀疏数组&#xff1f;2、稀疏数组的存储流程3、代码实现4、运行结果 1、什么是稀疏数组&#xff1f; 当一个数组中大部分元素为0&#xff0c;或者为同一个值的数组时&#xff0c;可以使用稀疏数组来保存该数组。 2、稀疏数组的存储流程 记录数组一共有几行…

活体检测(点头,摇头,张嘴等动态识别)

活体检测&#xff08;点头&#xff0c;摇头&#xff0c;张嘴等动态识别&#xff09; 某本书里有一句话&#xff0c;等我去读、去拍案。 田间的野老&#xff0c;等我去了解、去惊识。 山风与发&#xff0c;冷泉与舌&#xff0c; 流云与眼&#xff0c;松涛与耳&#xff0c; 他们等…

21、状态模式(行为性模式)

版本一、get状态指针 #include <iostream> using namespace std;//前置声明 class Context;//状态 class State{ public://4个状态virtual void toUp (Context& context){ }virtual void toDown (Context& context){ }virtual void toLeft (Context& cont…

架构学习总结:企业架构=业务+数据+技术+应用架构

最近再次研读DAMA数据管理知识体系,结合工作对什么是企业架构?如何开展企业架构设计工作有一些新的认识,供大家参考。企业架构包括企业的业务架构、数据架构、技术架构和应用架构,要想做好企业的信息化数字化建设规划,这四个架构都不可缺少,这四个方面的内容共同组成了企…

[云原生] k8s配置资源管理

一、Secret的资源配置 1.1 Secret配置的相关说明 Secret 是用来保存密码、token、密钥等敏感数据的 k8s 资源&#xff0c;这类数据虽然也可以存放在 Pod 或者镜像中&#xff0c;但是放在 Secret 中是为了更方便的控制如何使用数据&#xff0c;并减少暴露的风险。 Secret 有…

【JavaSE】抽象类与接口

Object 类 类 java.lang.Object是类层次结构的根类&#xff0c;即所有类的父类。 除Object类之外的任何一个Java类&#xff0c;全部直接或间接的继承于Object类。由此&#xff0c;Object类也被称为根父类。Object类中声明的成员具有通用性&#xff0c;并且Object类中没有声明…

300W-500W-700W-1000W超薄制动电阻

EAK制动电阻&#xff0c;最大连续功率&#xff1a;300 W--1000W 制动电阻器&#xff0c;用于带有中低功率变频器 或作为充电电阻器的驱动器。 安装在变频器附近。 防护等级 IP 20 / IP 54 可根据要求提供更高的防护等级 测试电压 2.5 kV AC 可根据要求提供其他容量和安装…

SMART PLC自适应低通滤波器(收放卷线速度滤波)

一阶低通滤波器更多内容请参考信号处理专栏相关文章,常用链接如下: 1、SMART PLC 低通滤波器和模拟量采集应用 https://rxxw-control.blog.csdn.net/article/details/136595982https://rxxw-control.blog.csdn.net/article/details/1365959822、SMART PLC双线性变换和后向差…

Docker笔记-进入运行中的镜像,查看日志等操作

docker搭建好后&#xff0c;查看运行的docker镜像&#xff1a; docker ps -a 进入运行的容器&#xff0c;命令如下&#xff1a; docker exec -it <容器ID> /bin/bash # 或者&#xff0c;直接用容器里面的命令&#xff0c;比如mysql镜像 docker exec -it <容器ID>…

网络协议常见问题

网络协议常见问题 OSI&#xff08;Open Systems Interconnection&#xff09;模型OSI 封装 TCP/IP协议栈IP数据报的报头TCP头格式UDP头格式TCP (3-way shake)三次握手建立连接&#xff1a;为什么三次握手才可以初始化 Socket、序列号和窗口大小并建立 TCP 连接。每次建立TCP连接…