前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试官:如何判断线程是否已经启动?

面试官:如何判断线程是否已经启动?

作者头像
田维常
发布2024-06-21 08:50:00
1020
发布2024-06-21 08:50:00
举报

你好,我是

一位朋友在面试中被问到:如何判断线程是否已经启动?

不想一开始就给出答案,而是逐步分析问题,掌握好知识的来龙去脉,不要把知识学的那么枯燥无味,不然你迟早要被劝退。

线程与进程

我们快速简单地了解一下线程与进程。

进程(Process)

定义 :进程是程序的一次执行过程,是系统资源分配的基本单位,每个进程之间相互独立。

特点

  • 拥有独立的内存空间和系统资源。
  • 可以包含多个线程,即多个线程共享进程的资源。
  • 进程之间通信相对复杂。

生活案例 :想象你在一台桌面电脑上打开了多个软件程序,比如同时运行着一个浏览器、一个文字处理软件以及一个视频播放器,每个软件就是一个独立的进程。每个软件有自己的内存空间和资源,彼此之间独立运行。

线程(Thread):

定义 :线程是进程内的执行单元,是 CPU 调度的基本单位,多个线程共享进程的资源。

特点

  • 共享进程的地址空间和系统资源。
  • 各个线程之间可以方便、快速地共享数据和通信。
  • 线程之间的切换较进程更快。

生活案例 :想象你在早晨做早饭的时候,同时负责煎蛋、煮咖啡和煮面,这就好比在一个进程中有多个线程在并行执行不同的任务。每个任务可以看作是一个线程,它们共享厨房这个整体资源。

不要一味地学技术以及背面试题,我们要想办法让技术回归生活案例中

总结
  • 进程是程序的一次执行,拥有独立的资源;线程是进程内的执行单元,共享进程的资源。
  • 进程之间相互独立,通信需要额外的机制;线程之间共享进程资源,通信更加方便快捷。
  • 操作系统负责进程调度和资源分配,而线程是在进程内部由程序员控制的。

线程创建方式

估计你也看过很多文章讲线程的创建方式有3种,4种,5种,6种,7种....。

不是说的种类越多显得你越牛X,而是要知道每一种的特点以及使用场景那才是真材实料。

我这里说三种,不想讲太多,没有多大意义。

1. 继承 Thread 类方式 :通过创建类并继承 Thread 类,重写 run() 方法来定义线程的执行逻辑。

代码语言:javascript
复制
// 继承 Thread 类创建线程
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread is running");
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建并启动线程
        MyThread thread = new MyThread();
        thread.start();
    }
}

这里有个很大的问题,那就是Java只支持单继承,为了解决单继承的问题咱们可以使用实现Runnable接口来创建线程。

2. 实现 Runnable 接口方式 :通过创建类实现 Runnable 接口,实现 run() 方法来定义线程的执行逻辑。然后将实现了 Runnable 接口的对象传递给 Thread 类的构造方法。

代码语言:javascript
复制
// 实现 Runnable 接口创建线程
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Runnable running");
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建线程并传入实现了 Runnable 接口的对象
        Thread thread = new Thread(new MyRunnable());
        thread.start();
    }
}

单继承的问题解决了,可是他们两都有个共同的问题:没有返回值

为此,我们可以使用实现Callable 接口来解决。

3.实现Callable接口 :使用 Callable 接口配合 Future 和 ExecutorService 来创建线程并返回结果。

代码语言:javascript
复制
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

// 实现 Callable 接口创建线程
class MyCallable implements Callable<String> {
    @Override
    public String call() {
        return "Callable thread is running";
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(1);

        // 提交 Callable 任务并获取 Future 对象
        Future<String> future = executor.submit(new MyCallable());

        try {
            // 获取线程执行结果
            String result = future.get();
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 关闭线程池
        executor.shutdown();
    }
}

通过实现 Callable 接口并重写 call() 方法来定义线程的执行逻辑。然后使用 ExecutorService 创建线程池并提交 Callable 任务,得到一个 Future 对象,通过该对象可以获取线程执行结束后的返回结果。

都是一环扣一环的,先是什么问题,解决了什么问题后,还是存在什么问题,又是怎么解决的。有点类似于我们做项目开发,很多时候我们的项目需要重构、拆分以及合并,都是为了解决某些问题。

线程状态

在我们Java语言中,线程的状态主要由 Thread.State 枚举类定义。这些状态描述了线程在其生命周期中可能经历的不同阶段。以下是 Java 中线程的几种状态:

NEW(新建) :当线程对象被创建但还未启动时,线程处于 NEW 状态。

RUNNABLE(可运行) :线程在操作系统中处于可运行状态,等待被调度执行。

BLOCKED(阻塞) :线程因为等待监视器锁(synchronized 关键字)而被阻塞。

WAITING(等待) :线程在等待特定条件触发的情况下进入等待状态,例如调用 Object.wait() 方法。

TIMED_WAITING(计时等待) :线程在有超时限制的情况下等待,例如调用带有超时参数的 Object.wait(timeout) 或 Thread.sleep(milliseconds) 方法。

TERMINATED(终止) :线程执行完毕或因异常退出时,线程处于终止状态。

在 Java 中,通过调用 getState() 方法可以获取线程的当前状态,返回的是 Thread.State 枚举类型。

这里需要注意:NEW状态时,说明线程还未启动,其他状态都表示线程已经启动了或启动后执行结束了。

线程常见方法

Thread 类提供了一些常用的方法来管理线程的执行和控制。以下是 Thread 类常见方法及其作用:

start() :启动线程,使线程进入就绪(runnable)状态,当获取到 CPU 时间片时开始执行线程的 run() 方法。

run() :线程的执行逻辑,需要在子类中重写这个方法来定义线程的任务。

sleep(long millis) :让当前线程休眠指定的时间(以毫秒为单位),线程进入阻塞状态,不会释放锁。

join() :等待调用该方法的线程执行完毕,当前线程会被阻塞,直到目标线程执行完毕。

interrupt() :中断线程,给该线程发出一个中断信号,线程可以在合适的时间响应中断。isInterrupted() 和 interrupted():

isInterrupted() :检查当前线程是否被中断,不会清除中断状态。

interrupted() :静态方法,检查当前线程是否被中断,会清除中断状态。

yield() :暂停当前正在执行的线程,让 CPU 调度器重新选择其他线程执行,可能会提高其他线程的执行机会。

isAlive() :检查线程是否存活,即线程已经启动但尚未终止,返回 boolean 值。

setName(String name) 和 getName()

  • setName(String name):设置线程的名称。
  • getName():获取线程的名称。

setPriority(int priority) 和 getPriority()

  • setPriority(int priority):设置线程的优先级,范围是 1 到 10,默认是 5。
  • getPriority():获取线程的优先级。

getState() :返回线程状态

关于线程的常见方法,很多人都不太关注,这可是有很多朋友面试被问到过的。

线程是否已经启动

聊了那么多线程相关知识,终于来到了今天的话题:线程是否已经启动?

下面,我用三种方式来和大家探讨。

第一种:使用Thread.currentThread().isAlive() 方法

Thread.currentThread().isAlive()方法用于检查当前线程是否处于活动状态。如果线程已经启动且尚未终止,则返回true,否则返回false。

代码语言:javascript
复制
Thread thread = new Thread(() -> {
    // 线程执行的任务
});

// 判断线程是否启动
if (thread.isAlive()) {
    System.out.println("线程已启动");
} else {
    System.out.println("线程未启动");
}
第二种:使用 getState() 方法

通过调用getState()方法可以获取线程的状态,常见的状态包括NEW(新建)、RUNNABLE(可运行)、TIMED_WAITING(计时等待)等。

代码语言:javascript
复制
Thread thread = new Thread(() -> {
    // 线程执行的任务
});

// 获取线程状态
Thread.State state = thread.getState();

if (state == Thread.State.NEW) {
    System.out.println("线程尚未启动");
} else {
    System.out.println("线程已启动");
}
第三种:使用 布尔变量或状态标记

在线程类中添加一个布尔变量或状态标记,来表示线程是否已经启动或结束。

代码语言:javascript
复制
class MyThread extends Thread {
    private boolean isStarted = false;

    @Override
    public void run() {
        isStarted = true;
        // 执行任务
    }

    public boolean isThreadStarted() {
        return isStarted;
    }
}

MyThread thread = new MyThread();
thread.start();

// 判断线程是否启动
if (thread.isThreadStarted()) {
    System.out.println("线程已启动");
} else {
    System.out.println("线程未启动");
}

总结

本文从线程与进程开始聊,再聊到了线程的创建方式、线程的状态、线程常见方法,最后再来聊了如何判断线程是否已经启动。希望这种思路能让你更轻松的掌握这个问题,另外,强烈建议在学技术时,最好是把技术回归到我们生活案例中。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java后端技术全栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 线程与进程
    • 进程(Process)
      • 线程(Thread):
        • 总结
        • 线程创建方式
        • 线程状态
        • 线程常见方法
        • 线程是否已经启动
          • 第一种:使用Thread.currentThread().isAlive() 方法
            • 第二种:使用 getState() 方法
              • 第三种:使用 布尔变量或状态标记
              • 总结
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档