赞
踩
Java线程6种状态和工作原理详解,Java创建线程的4种方式
在并发编程领域,Java线程是实现多任务处理的基石。了解其状态及工作原理对于开发高效、稳定的Java应用至关重要。本文将深入探讨Java线程的各种状态以及它们的工作机制。
Java线程在其生命周期内可以处于以下几种状态:
start()
方法之前的状态。start()
方法后的状态。在此状态,线程可能正在运行也可能正在等待CPU分配时间片,具体取决于操作系统的线程调度器。Object.wait()
、Thread.join()
或LockSupport.park()
),该线程会进入等待状态。sleep()
, wait()
, join()
, 或LockSupport.parkNanos()
/parkUntil()
时,会处于该状态。- 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虚拟机(JVM)通过映射到底层操作系统的原生线程实现来管理Java线程。这个过程主要包括线程的创建、调度、上下文切换、以及终止等方面。
start()
方法时,JVM会向操作系统请求创建一个新的线程。操作系统为此分配资源并开始执行线程的run()
方法。notify()
、notifyAll()
方法)将其唤醒。此时,线程再次竞争获取必要的锁以继续执行。线程的工作模式是,首先先要创建线程并指定线程需要执行的业务方法,然后再调用线程的 start() 方法,此时线程就从 NEW(新建)状态变成了 RUNNABLE(就绪)状态,此时线程会判断要执行的方法中有没有 synchronized 同步代码块,如果有并且其他线程也在使用此锁,那么线程就会变为 BLOCKED(阻塞等待)状态,当其他线程使用完此锁之后,线程会继续执行剩余的方法。
当遇到 Object.wait() 或 Thread.join() 方法时,线程会变为 WAITING(等待状态)状态,如果是带了超时时间的等待方法,那么线程会进入 TIMED_WAITING(计时等待)状态,当有其他线程执行了 notify() 或 notifyAll() 方法之后,线程被唤醒继续执行剩余的业务方法,直到方法执行完成为止,此时整个线程的流程就执行完了,执行流程如下图所示:
虽然 BLOCKED 和 WAITING 都有等待的含义,但二者有着本质的区别,首先它们状态形成的调用方法不同,其次 BLOCKED 可以理解为当前线程还处于活跃状态,只是在阻塞等待其他线程使用完某个锁资源;而 WAITING 则是因为自身调用了 Object.wait() 或着是 Thread.join() 又或者是 LockSupport.park() 而进入等待状态,只能等待其他线程执行某个特定的动作才能被继续唤醒,比如当线程因为调用了 Object.wait() 而进入 WAITING 状态之后,则需要等待另一个线程执行 Object.notify() 或 Object.notifyAll() 才能被唤醒。
首先从 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;
-
- @Override
- public void run() {
- if (target != null) {
- target.run();
- }
- }
- }
-
- @FunctionalInterface
- public interface Runnable {
- public abstract void run();
- }
Java提供了多种创建和管理线程的方式,从简单的Thread
类继承到实现Runnable
或Callable
接口,再到使用强大的线程池管理。
选择合适的方式取决于具体的应用场景和需求。对于简单的任务,直接使用Thread
类或Runnable
接口可能就足够了。而对于需要任务执行结果的情况,Callable
接口将是更好的选择。
在处理大量并发任务时,利用线程池可以显著提高性能和资源利用率。了解和掌握这些方法,对于编写高效、稳定的Java多线程程序至关重要。
Thread
类Java允许通过继承Thread
类的方式创建线程。这种方式简单直观,适用于简单的线程任务。
- class MyThread extends Thread {
- @Override
- public void run() {
- // 这里填写线程任务代码
- System.out.println("线程运行中...");
- }
- }
-
- public class ThreadExample {
- public static void main(String[] args) {
- MyThread t = new MyThread();
- t.start(); // 启动新线程
- }
- }
Runnable
接口实现Runnable
接口是创建线程最常见的方式之一,它提供了更大的灵活性,允许线程类继承其他类。
- class MyRunnable implements Runnable {
- @Override
- public void run() {
- // 线程任务
- System.out.println("通过Runnable接口运行线程...");
- }
- }
-
- public class RunnableExample {
- public static void main(String[] args) {
- Thread t = new Thread(new MyRunnable());
- t.start(); // 启动线程
- }
- }
Callable
接口与FutureTask
Callable
接口类似于Runnable
,但它可以返回执行结果,并且能抛出异常。
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.FutureTask;
-
- class MyCallable implements Callable<Integer> {
- @Override
- public 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);
- }
- }
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、使用线程池】的所有方式
如果本文对你有帮助 欢迎 关注 、点赞 、收藏 、评论, 博主才有动力持续记录遇到的问题!!!
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/357785
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。