Java中Thread类详解及常用的方法

Java中Thread类详解及常用的方法

在Java中,Thread类是用来实现多线程编程的核心类。每个Java应用程序都至少有一个线程,这个线程是由JVM(Java 虚拟机)创建的,并且负责程序的主方法的执行。不仅如此,除了主线程,Java应用程序可以有其他线程,这些线程可以是由主线程或其他线程创建的,Java 中的 Thread 类就是用于实现这些线程的。

创建并启动一个线程

创建Thread对象的第一种方法是实现Runnable接口。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("MyRunnable is running.");
    }
}

public class Test {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

以上代码展示了第一种方法的实现。可以看到,我们首先定义了一个实现了Runnable接口的类 MyRunnable。在这个类中,我们实现了run()方法,并在其中写下了我们想让线程执行的代码。接着,我们创建了一个 MyRunnable的实例,并将其作为参数传递给Thread类的构造函数。最后,我们调用 start()方法开始执行该线程。

创建Thread对象的第二种方法是继承Thread类。

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("MyThread is running.");
    }
}

public class Test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}

从以上代码中,我们可以看到,MyThread类继承了 Thread类,并实现了run()方法。在主方法中,我们创建了一个 MyThread的实例,并直接调用它的start()方法开始执行该线程。

线程方法

start()

start()方法用来启动线程,调用该方法使得线程进入就绪状态。当线程获得 CPU 时间片后,就开始执行 run()方法。

join()

当一个线程调用另一个线程的join()方法时,调用线程将被阻塞,直到被调用线程执行完为止。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("MyRunnable is running.");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("MyRunnable is finished.");
    }
}

public class Test {
    public static void main(String[] args) throws InterruptedException {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
        System.out.println("Main thread is running.");
        thread.join();
        System.out.println("Main thread is finished.");
    }
}

以上代码中, join()方法被调用后,主线程将被阻塞,直到线程 thread 执行完后,主线程才会继续执行。

yield()

在一个多线程应用中,线程运行时常常需要等待某个事件的发生,但并不能确定该事件究竟要等多少时间。在这种情况下,可以使用 yield()方法来使得线程放弃当前的 CPU 时间片,让其它线程运行。

class MyRunnable1 implements Runnable {
    @Override
    public void run() {
        System.out.println("MyRunnable1 is running.");
        Thread.yield();
        System.out.println("MyRunnable1 is finished.");
    }
}

class MyRunnable2 implements Runnable {
    @Override
    public void run() {
        System.out.println("MyRunnable2 is running.");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("MyRunnable2 is finished.");
    }
}

public class Test {
    public static void main(String[] args) throws InterruptedException {
        MyRunnable1 myRunnable1 = new MyRunnable1();
        MyRunnable2 myRunnable2 = new MyRunnable2();
        Thread thread1 = new Thread(myRunnable1);
        Thread thread2 = new Thread(myRunnable2);
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println("Main thread is finished.");
    }
}

MyRunnable1线程执行到 yield()方法时,其它线程将有机会获得 CPU 时间片。

sleep()

sleep()方法让当前正在执行的线程休眠指定的时间,在这段时间内,线程暂时释放CPU控制权,其他线程得以运行。sleep()方法会抛出一个异常InterruptedException,所以在使用sleep()方法时通常要捕获这个异常。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("MyRunnable is running.");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("MyRunnable is finished.");
    }
}

public class Test {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

以上代码中, MyRunnable线程在执行到Thread.sleep(2000)方法时将会休眠2秒钟。

线程状态

一个线程在它的生命周期中可能处于以下五个状态的任意一个状态。

  1. 新建状态(New):刚刚创建一个线程对象时,它处于新建状态
  2. 就绪状态(Runnable):当调用start()方法后,线程进入就绪状态
  3. 运行状态(Running):当就绪状态的线程被调度并获得CPU执行时间,它就进入运行状态
  4. 阻塞状态(Blocked)或等待状态(Waiting)或计时等待状态(Time Waiting):当线程执行一个同步方法时,线程因为不能获取到所需的锁而进入阻塞状态;线程调用了wait()方法,进入等待状态;线程调用了sleep()方法或调用了带有超时参数的方法,进入计时等待状态。
  5. 终止状态(Terminated):当线程执行完毕或者发生了一个未捕获的异常并被有效地处理后,线程处于终止状态。

示例说明

以下示例将创建两个线程,并展示它们的不同状态。

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("MyThread is running.");
        System.out.println("MyThread state is " + this.getState().toString());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("MyThread is finished.");
        System.out.println("MyThread state is " + this.getState().toString());
    }
}

public class Test {
    public static void main(String[] args) {
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();
        System.out.println("Thread1 state is " + myThread1.getState().toString());
        System.out.println("Thread2 state is " + myThread2.getState().toString());
        myThread1.start();
        myThread2.start();
        System.out.println("Thread1 state is " + myThread1.getState().toString());
        System.out.println("Thread2 state is " + myThread2.getState().toString());
    }
}

以上代码中,我们创建了两个 MyThread线程,并在主方法中获取了它们的状态。然后,我们启动了这两个线程,并再次获取它们的状态。最终,我们顺序等待这两个线程执行完成后,再次获取它们的状态。

输出:

Thread1 state is NEW
Thread2 state is NEW
MyThread is running.
Thread1 state is RUNNABLE
Thread2 state is RUNNABLE
MyThread is running.
MyThread state is RUNNABLE
Thread1 state is TIMED_WAITING
Thread2 state is RUNNABLE
MyThread is finished.
MyThread state is TERMINATED
Thread1 state is TERMINATED
Thread2 state is TIMED_WAITING
MyThread is finished.
MyThread state is TERMINATED
Thread2 state is TERMINATED

可以看到,线程在被创建后,初始状态为 NEW;在调用了 start()方法后,状态变为了 RUNNABLE。在一个线程正在执行时,状态为 RUNNING;在一个线程正在等待获取一个锁的时候,状态为 BLOCKED。而当一个线程执行 wait()方法时,线程会进入等待状态,状态为 WAITING;当线程调用 sleep()方法或带有超时参数的方法时,进入计时等待状态,状态为 TIMED_WAITING。对于已经完成工作的线程,其状态为 TERMINATED

另外,需要注意的是,getState()方法不是同步的。如果它被调用时线程正在运行,并且线程的状态正在变化,那么可能会无法获取到准确的状态。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中Thread类详解及常用的方法 - Python技术站

(0)
上一篇 2023年5月18日
下一篇 2023年5月18日

相关文章

  • Flash 实用代码总汇第1/2页

    我们来详细讲解一下“Flash 实用代码总汇第1/2页”的完整攻略。 1. 概述 本篇攻略主要介绍了 Flash 实用代码总汇第1/2页 的使用方法,其中包含了有关 Flash 常用代码的分类、查找和使用等方面的内容。该代码总汇包含了许多 Flash 动画制作过程中可能用到的代码,对于 Flash 初学者或是想要提高 Flash 制作技能的人来说都是非常有用…

    Java 2023年6月15日
    00
  • Lombok基本注解之@SneakyThrows的作用

    下面是关于Lombok基本注解之@SneakyThrows的作用的完整攻略。 1. @SneakyThrows简介 在Java中,我们通常使用try-catch语句捕获异常。但是,有时候代码中出现的异常并不是我们想要处理的,而是完全出乎意料的异常情况,这时候需要抛出异常。抛出异常通常要求在方法签名上声明当前方法可能会抛出某种类型的异常,这会使代码变得冗长,甚…

    Java 2023年5月26日
    00
  • Kotlin编程基础语法编码规范

    Kotlin编程基础语法编码规范 1. 常见命名规范 在Kotlin语言中,标识符的命名规范如下: 包名使用小写字母: 包名应该全部使用小写字母,且不应该使用下划线或者其它特殊字符。 类名使用驼峰命名: 类名的首字母应该大写,驼峰命名,不使用下划线。 方法名使用小驼峰命名: 方法名的首字母应该小写,而后面的单词首字母应该大写。 常量名使用全大写字母: 常量名…

    Java 2023年6月1日
    00
  • 如何用struts调用支付宝接口

    下面是如何用struts调用支付宝接口的攻略。 1.准备工作 在使用struts调用支付宝接口之前,需要先完成以下准备工作: 1.申请支付宝开发者账号:在支付宝开放平台注册账号,并完成实名认证。 2.创建应用:登录开放平台后,在开发者控制台创建一个应用,并得到应用的APP ID、商户私钥、支付宝公钥等信息。 3.下载支付宝开发包:在[支付宝开放平台](htt…

    Java 2023年5月20日
    00
  • Spring注解方式无法扫描Service注解的解决

    当使用Spring注解方式配置应用程序时,有时可能会出现在扫描Service注解时无法识别的问题。出现这个问题的原因一般是因为缺少在Spring中定义Service注解扫描器的配置或者配置错误。解决此类问题需要进行以下设置: 添加@Service注解扫描器。 要使Spring扫描@Service注解,需要在Spring配置文件中配置注解扫描器,如下所示: &…

    Java 2023年5月20日
    00
  • Spring Boot2.3 新特性分层JAR的使用

    文章标题:SpringBoot2.3新特性分层JAR的使用 一、前言 在 2.3 版本发布之后,SpringBoot 推出了一个新特性——分层 JAR(Layered JAR)。本文将详细介绍分层 JAR 的概念,用法和示例。 二、概念 在过去,当你用 SpringBoot 来打包应用程序时所得到的 JAR 文件中包含了所有的类,依赖和资源。虽然这种方式简单…

    Java 2023年5月15日
    00
  • SpringBoot启动原理深入解析

    SpringBoot启动原理深入解析 什么是SpringBoot? SpringBoot是基于Spring框架的一套快速开发框架,采用约定优于配置的思想,目的在于简化Spring应用的创建和开发过程。 SpringBoot启动过程 SpringBoot启动过程涉及到的类和接口有很多,下面对SpringBoot启动过程的核心部分做一个简单的介绍。 Spring…

    Java 2023年5月15日
    00
  • Java中的运算符重载是什么?

    Java中的运算符重载是指允许在自定义的类中对运算符(如+、-、*、/等)进行重新定义,以便对自定义的类进行运算。运算符重载的本质是将运算符号的含义进行扩展,使得一种运算符号能够被用于多种类型的数据操作。 运算符重载是实现多态性的一个重要技巧。对于类中的不同对象,运算符的行为可以有所不同,这样可以减少代码的冗余,提高代码的复用性。 运算符重载实现起来比较简单…

    Java 2023年4月27日
    00
合作推广
合作推广
分享本页
返回顶部