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

posted @   垄山小站  阅读(71)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)
点击右上角即可分享
微信分享提示