Java基础知识(12)- Java 多线程编程(一) | 线程的生命周期、优先级、创建线程
Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。
进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。
多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。
1. 线程的生命周期
线程是一个动态执行的过程,它也有一个从产生到死亡的过程。
下图显示了一个线程完整的生命周期。
新建状态 --> 就绪状态 --> 运行状态 -> 死亡状态
| |
<-- 阻塞状态 <--
1) 新建状态:
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
2) 就绪状态:
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
3) 运行状态:
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
4) 阻塞状态:
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
(1) 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
(2) 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
(3) 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
5) 死亡状态:
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
2. 线程的优先级
每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。
Java 线程的优先级是一个整数,其取值范围是(数值大优先级高):
1 (Thread.MIN_PRIORITY )
2
...
9
10 (Thread.MAX_PRIORITY )
默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。
具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。
3. 创建线程
Java 实现多线程的三种创建方式。
1) 通过继承 Thread 类:
1 class FirstThread extends Thread { 2 public void run() { 3 // 执行代码 4 } 5 } 6 7 public class App { 8 public static void main( String[] args ) { 9 FirstThread firstThread = new FirstThread(); 10 firstThread.start(); 11 } 12 }
2) 通过实现 Runnable 接口:
1 class SecondThread extends Thread implements Runnable { 2 SecondThread(String name) { 3 this.setName(name); 4 }
5
6 public void run() { 7 // 执行代码
8 } 9 } 10 11 public class App { 12 public static void main( String[] args ) { 13 SecondThread secondThread = new SecondThread(); 14 secondThread.start(); 15 } 16 }
3) 通过实现 Callable 接口:
1 class ThirdThread implements Callable<Integer> { 2 Thread t; 3 FutureTask<Integer> futureTaskCallable; 4 5 ThirdThread() { 6 futureTaskCallable = new FutureTask<>(this); 7 t = new Thread(futureTaskCallable); 8 } 9 10 @Override 11 public Integer call() throws Exception { 12 // 执行代码 13 } 14 15 public void start(){ 16 t.start(); 17 } 18 } 19 20 public class App { 21 public static void main( String[] args ) { 22 ThirdThread thirdThread = new ThirdThread(); 23 thirdThread.start(); 24 } 25 }
三种方式的比较:
(1) 采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
(2) 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。
实例:
1 import java.util.concurrent.Callable; 2 import java.util.concurrent.ExecutionException; 3 import java.util.concurrent.FutureTask; 4 5 public class App { 6 public static void main( String[] args ) { 7 8 FirstThread firstThread = new FirstThread("First Thread"); 9 firstThread.start(); 10 11 SecondThread secondThread = new SecondThread("Second Thread"); 12 secondThread.start(); 13 14 ThirdThread thirdThread = new ThirdThread("Third Thread"); 15 thirdThread.start(); 16 17 try { 18 System.out.println("Third Thread return:" + thirdThread.getReturnValue()); 19 } catch (InterruptedException e) { 20 e.printStackTrace(); 21 } catch (ExecutionException e) { 22 e.printStackTrace(); 23 } 24 25 } 26 } 27 28 // 通过继承 Thread 创建线程 29 class FirstThread extends Thread { 30 31 public FirstThread(String name) { 32 super(name); 33 System.out.println(name + ": " + this); 34 } 35 36 public void run() { 37 try { 38 for (int i = 5; i > 0; i--) { 39 System.out.println(this.getName() + ": " + i); 40 Thread.sleep(1000); 41 } 42 } catch (InterruptedException e) { 43 System.out.println(this.getName() + " interrupted."); 44 } 45 System.out.println("Exiting " + this.getName() + " ... "); 46 } 47 } 48 49 // 通过实现 Runnable 接口创建线程 50 class SecondThread extends Thread implements Runnable { 51 SecondThread(String name) { 52 this.setName(name); 53 System.out.println(t.getName() + ": " + t); 54 } 55 56 public void run() { 57 try { 58 for(int i = 5; i > 0; i--) { 59 System.out.println(t.getName() + ": " + i); 60 Thread.sleep(1000); 61 } 62 } catch (InterruptedException e) { 63 System.out.println(t.getName() + " interrupted."); 64 } 65 System.out.println("Exiting " + t.getName() + " ... "); 66 } 67 } 68 69 // 通过实现 Callable 接口创建线程 70 class ThirdThread implements Callable<Integer> { 71 Thread t; 72 FutureTask<Integer> futureTaskCallable; 73 74 ThirdThread(String name) { 75 futureTaskCallable = new FutureTask<>(this); 76 t = new Thread(futureTaskCallable, name); 77 System.out.println(name + ": " + t); 78 } 79 80 @Override 81 public Integer call() throws Exception { 82 int i = 0; 83 for(; i<5; i++) { 84 System.out.println(t.getName() + ": " + i); 85 Thread.sleep(1000); 86 } 87 System.out.println("Exiting " + t.getName() + " ... "); 88 return i; 89 } 90 91 public void start(){ 92 t.start(); 93 } 94 95 public Integer getReturnValue() throws InterruptedException, ExecutionException { 96 return futureTaskCallable.get(); 97 } 98 99 }
输出:
First Thread: Thread[First Thread,5,main]
First Thread: 5
Second Thread: Thread[Second Thread,5,main]
Second Thread: 5
Third Thread: Thread[Third Thread,5,main]
Third Thread: 0
Third Thread: 1
Second Thread: 4
First Thread: 4
Second Thread: 3
First Thread: 3
Third Thread: 2
Second Thread: 2
Third Thread: 3
First Thread: 2
First Thread: 1
Third Thread: 4
Second Thread: 1
Exiting Second Thread ...
Exiting Third Thread ...
Exiting First Thread ...
Third Thread return:5
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)