。# Java什么是线程?全面解析线程概念、生命周期及创建方法【新手必看】
一、Java中线程的定义:什么是线程?
在Java编程中,线程(Thread) 是进程(Process) 中的一个单一顺序控制流,是程序执行的最小单位。
如果用生活中的例子类比:
进程就像一个“正在运行的工厂”(比如打开的浏览器程序),包含了操作系统分配的内存、CPU等资源;
线程则是工厂中的“一条生产线”,负责完成具体的任务(比如浏览器中的“网页渲染”“下载文件”等子任务)。
一个进程可以同时包含多个线程(比如浏览器可以同时加载网页、播放视频、下载文件),这些线程共享进程的内存空间(如堆内存),但各自拥有独立的执行栈(Stack)和程序计数器(Program Counter),因此可以并行执行不同的任务,提高程序的运行效率。
二、线程与进程的核心区别(新手必懂)
很多新手会混淆“线程”和“进程”,这里用表格对比帮你快速区分:
特征 进程 线程
资源分配 独立分配内存、CPU等系统资源 共享所属进程的资源(如内存、文件句柄)
执行单位 操作系统调度的基本单位 进程内调度的基本单位
上下文切换 开销大(需切换内存映射、寄存器等) 开销小(只需切换执行栈、程序计数器)
通信方式 需通过IPC(如管道、Socket) 可通过共享变量直接通信(需同步)
稳定性 进程崩溃不影响其他进程 线程崩溃可能导致整个进程崩溃
三、Java线程的生命周期:从创建到死亡的五个阶段
Java线程的一生会经历5个状态,由JVM(Java虚拟机)的线程调度器管理,状态转换如下:
1. 新建状态(New)
当用new关键字创建线程对象(如new Thread)时,线程处于新建状态。此时线程尚未启动,仅占用堆内存中的对象空间。
示例:
Thread thread = new Thread; // 新建状态
2. 就绪状态(Runnable)
调用线程对象的start方法后,线程进入就绪状态。此时线程已准备好执行,但需等待JVM分配CPU资源(即“排队”等待调度)。
示例:
thread.start; // 进入就绪状态,等待CPU调度
3. 运行状态(Running)
当就绪状态的线程获得CPU资源后,开始执行run方法中的代码,此时线程处于运行状态。这是线程最活跃的状态。
注意:
线程在运行状态中可能会被抢占(如更高优先级的线程到来),回到就绪状态;
线程执行yield方法(礼让)也会主动放弃CPU,回到就绪状态。
4. 阻塞状态(Blocked)
当线程因某种原因失去CPU资源时,进入阻塞状态。常见的阻塞场景包括:
执行sleep(long millis)方法(睡眠);
等待同步锁(synchronized未获取到锁);
执行wait方法(等待通知);
进行I/O操作(如读取文件、网络请求)。
示例:
Thread.sleep(1000); // 睡眠1秒,进入阻塞状态
5. 死亡状态(Dead)
当线程完成run方法中的所有代码,或被interrupt方法中断(且未捕获异常),或因异常崩溃时,线程进入死亡状态。此时线程无法再被启动(调用start会抛出IllegalThreadStateException)。
四、Java创建线程的三种方法(附示例代码)
Java提供了三种创建线程的方式,各有优缺点,适合不同场景:
1. 实现Runnable接口(推荐)
步骤:
实现Runnable接口,重写run方法(定义线程执行的任务);
创建Runnable对象,作为参数传入Thread构造函数;
调用Thread对象的start方法启动线程。
示例代码:
// 实现Runnable接口 public class MyRunnable implements Runnable {
@Override public void run {
System.out.println(" 线程任务:通过Runnable接口创建线程,线程ID:" + Thread.currentThread.getId);
}
public static void main(String[] args) {
// 创建Runnable对象 MyRunnable runnable = new MyRunnable;
// 传入Thread构造函数 Thread thread = new Thread(runnable);
// 启动线程 thread.start;
}
}
优点:
避免了Thread类的单继承限制(Java中类只能单继承,但可以实现多个接口);
更符合“面向接口编程”的设计原则,代码扩展性更好。
2. 继承Thread类(不推荐)
步骤:
继承Thread类,重写run方法;
创建Thread子类对象,调用start方法启动线程。
示例代码:
// 继承Thread类public class MyThread extends Thread {
@Override public void run {
System.out.println(" 线程任务:通过继承Thread类创建线程,线程名称:" + Thread.currentThread.getName);
}
public static void main(String[] args) {
// 创建Thread子类对象 MyThread thread = new MyThread;
// 启动线程 thread.start;
}
}
缺点:
由于Java单继承的限制,子类无法再继承其他类,灵活性差;
线程任务与线程对象耦合度高,不利于代码复用。
3. 使用Callable和Future(获取返回值)
场景:需要线程执行完成后返回结果(如计算任务)。
步骤:
实现Callable<T>接口(T为返回值类型),重写call方法(可抛出异常);
创建Callable对象,包装成FutureTask<T>(兼具Runnable和Future的特性);
将FutureTask传入Thread构造函数,调用start方法启动线程;
通过FutureTask的get方法获取返回值(会阻塞直到结果返回)。
示例代码:
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
// 实现Callable接口(返回String类型)public class MyCallable implements Callable<String> {
@Override public String call throws Exception {
Thread.sleep(2000); // 模拟耗时任务 return "线程任务完成,返回结果:" + Thread.currentThread.getName;
}
public static void main(String[] args) throws Exception {
// 创建Callable对象 MyCallable callable = new MyCallable;
// 包装成FutureTask FutureTask<String> futureTask = new FutureTask<>(callable);
// 传入Thread构造函数并启动 Thread thread = new Thread(futureTask);
thread.start;
// 获取返回值(会阻塞直到结果返回) String result = futureTask.get;
System.out.println(" 收到返回结果:" + result);
}
}
优点:
可以获取线程执行的返回值;
可以处理线程执行中的异常(get方法会抛出ExecutionException)。
五、Java线程的常见问题与注意事项(新手避坑)
不要直接调用run方法:
run方法是普通方法,直接调用不会启动新线程(只会在当前线程中执行run中的代码)。必须调用start方法才能启动新线程。
线程优先级不保证执行顺序:
Java线程的优先级范围是1(最低)到10(最高),默认优先级为5。优先级高的线程更有可能被调度,但无法保证绝对顺序(依赖操作系统的调度算法)。
避免使用stop和suspend方法:
这两个方法已被标记为过时(Deprecated),因为它们不安全:stop会强制终止线程,可能导致资源未释放;suspend会导致线程挂起,可能引发死锁。推荐使用interrupt方法中断线程(需配合isInterrupted判断)。
多线程共享资源需同步:
当多个线程访问共享资源(如全局变量、集合)时,需使用同步机制(如synchronized关键字、Lock接口),避免线程安全问题(如数据不一致、脏读)。
总结:Java线程是多任务编程的基础
通过本文的讲解,相信你已经理解了“Java什么是线程”的核心概念,掌握了线程的生命周期和创建方法。
关键结论:
线程是进程中的最小执行单位,共享进程资源;
推荐使用Runnable接口创建线程(避免单继承限制);
多线程编程需注意线程安全和调度问题。
如果想深入学习多线程,建议进一步研究同步机制(synchronized、Lock)、并发包(java.util.concurrent )和线程池(ExecutorService)等内容,这些都是Java高级编程的核心知识点。
最后:如果本文对你有帮助,欢迎点赞、收藏,转发给需要的朋友!