Java有哪几种方式创建线程?

简介: 本文详细介绍了Java中创建线程的四种主要方法:继承`Thread`类、实现`Runnable`接口、实现`Callable`接口配合`Future`,以及使用`Executor`框架。每种方法都有其独特特性和适用场景。通过示例代码和特点分析,帮助开发者根据具体需求选择合适的方式。

嗨,你好,我是猿java

这篇文章,我们继续分析一道面试题:Java有几种方式创建线程?

从应用层面来说,Java 中创建线程的方式主要有四种:

  1. 通过继承 Thread 类
  2. 通过实现 Runnable 接口
  3. 通过实现 Callable 接口配合 Future
  4. 通过使用 Executor 框架。

每种方法都有其独特的特性和适用场景,下面我们将分别讲解4种方式。

继承 Thread 类

通过继承 Thread类来创建线程是 Java中最简单,最基本的方法之一。每一个Thread实例代表着一个单独的执行线程,通过重写 Thread类的run()方法,我们可以定义线程要执行的操作,调用start()方法时,JVM会创建一个新的操作系统线程,并在该线程上调用run()方法。

示例代码:

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

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

特点和适用场景:

  • 直接使用继承的方式,代码清晰易懂。
  • 由于 Java 只支持单继承,当你的类需要继承其他类时,继承 Thread 类的方法就不适用了。

实现 Runnable 接口

实现Runnable接口是一种更灵活的创建线程的方式。Runnable接口只定义了一个方法run(),通过实现该接口的类并将其实例传递给Thread对象,我们可以将想要执行的任务分离成单独的类。

示例代码:

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

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

特点和适用场景:

  • 适用于希望在多个线程中共享相同任务的场景。
  • 避免了单继承的限制。

实现 Callable 接口配合 Future

Callable 接口与 Runnable 接口类似,但不同的是 Callable 可以返回结果或抛出异常。通常与FutureExecutorService结合使用,ExecutorService管理线程的生命周期,Future对象可以获取线程的执行结果或状态。

示例代码:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

class MyCallable implements Callable<String> {
   
    @Override
    public String call() throws Exception {
   
        return "Thread is running using Callable interface.";
    }
}

public class Main {
   
    public static void main(String[] args) {
   
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new MyCallable());

        try {
   
            String result = future.get();
            System.out.println(result);
        } catch (InterruptedException | ExecutionException e) {
   
            e.printStackTrace();
        } finally {
   
            executor.shutdown();
        }
    }
}

特点和适用场景:

  • 适合需要任务返回结果或监控任务状态的场景。
  • 相比 RunnableCallable 可以抛出检查型异常。

使用Executor框架(线程池)

Executor 框架是 Java 并发编程的基础结构,分离了任务的提交和任务的执行。通过 ExecutorService 提交任务,可以通过复用线程来提高性能,降低系统资源的开销,然后框架负责管理线程池、任务调度等。

示例代码:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
   
    public static void main(String[] args) {
   
        ExecutorService executor = Executors.newFixedThreadPool(3);

        Runnable task = () -> {
   
            System.out.println("Thread is running using Executor framework.");
        };

        for (int i = 0; i < 5; i++) {
   
            executor.submit(task);
        }

        executor.shutdown();
    }
}

特点和适用场景:

  • 非常适合需要多个线程或线程池来管理任务的复杂场景。
  • 提高应用程序的可伸缩性和资源使用率。
  • 管理线程池的生命周期和任务调度,降低难度。

如何选择?

  1. 代码重用性与继承关系:继承 Thread 类的方式由于 Java 的单继承特性可能不够灵活,尤其是在类需要从其他类继承时。使用 RunnableCallable 会更适合此类场景。

  2. 返回结果和异常处理:如果任务需要返回结果或需要处理异常,Callable 配合 Future 是更好的选择。相比之下,Runnable 不支持返回任务执行的结果。

  3. 任务管理:对于任务的管理和调度,尤其是涉及到线程的生命周期管理时,Executor 框架提供了更好的抽象和工具支持。框架本身负责优化线程的创建与销毁。

  4. 易用性:继承 Thread 或实现 Runnable 都是较为简单和直观的方法,适合初学者或较简单的任务。

  5. 性能与可伸缩性Executor 框架不仅能提供方便的任务执行接口,还能为复杂应用的性能优化提供支持,如根据服务器资源动态调整线程池大小。

总结

线程是 Java的最小执行单元,Java如何创建线程是个古老又重要的话题和面试题,这篇文章我们又啰嗦了一遍。作为开发人员,选择哪种方式创建线程,需要结合应用的具体需求和特点,但是,无论选择哪种方式,理解每种方法的原理,特点与适用场景在实际开发中都至关重要。

学习交流

如果你觉得文章有帮助,请帮忙转发给更多的好友,或关注:猿java,持续输出硬核文章。

目录
相关文章
|
18天前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
37 2
|
7天前
|
Java 关系型数据库 MySQL
如何用java的虚拟线程连接数据库
本文介绍了如何使用Java虚拟线程连接数据库,包括设置JDK版本、创建虚拟线程的方法和使用虚拟线程连接MySQL数据库的示例代码。
20 6
如何用java的虚拟线程连接数据库
|
3天前
|
监控 Java Linux
Java 性能调优:调整 GC 线程以获得最佳结果
Java 性能调优:调整 GC 线程以获得最佳结果
30 11
|
10天前
|
Java 数据库 UED
Java的多线程有什么用
Java的多线程技术广泛应用于提升程序性能和用户体验,具体包括:提高性能,通过并行执行充分利用多核CPU;保持响应性,使用户界面在执行耗时操作时仍流畅交互;资源共享,多个线程共享同一内存空间以协同工作;并发处理,高效管理多个客户端请求;定时任务,利用`ScheduledExecutorService`实现周期性操作;任务分解,将大任务拆分以加速计算。多线程尤其适用于高并发和并行处理场景。
|
1天前
|
Java 开发者
在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选
【10月更文挑战第6天】在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选。相比 `synchronized`,Lock 提供了更灵活强大的线程同步机制,包括可中断等待、超时等待、重入锁及读写锁等高级特性,极大提升了多线程应用的性能和可靠性。通过示例对比,可以看出 Lock 接口通过 `lock()` 和 `unlock()` 明确管理锁的获取和释放,避免死锁风险,并支持公平锁选择和条件变量,使其在高并发场景下更具优势。掌握 Lock 接口将助力开发者构建更高效、可靠的多线程应用。
6 2
|
6天前
|
Java 调度
Java一个线程的生命周期详解
Java中,一个线程的生命周期分为五个阶段:NEW(新建),RUNNABLE(可运行),BLOCKED(阻塞),WAITING(等待),TERMINATED(终止)。线程创建后处于新建状态,调用start方法进入可运行状态,执行中可能因等待资源进入阻塞或等待状态,正常完成或异常终止后进入终止状态。各状态间可相互转换,构成线程的生命周期。
|
22天前
|
存储 缓存 Java
java线程内存模型底层实现原理
java线程内存模型底层实现原理
java线程内存模型底层实现原理
|
6天前
|
Java API 调度
Java 多线程编程详解
《Java多线程编程详解》深入浅出地讲解了Java平台下的多线程核心概念、API使用及最佳实践。从基础理论到实战案例,本书帮助读者掌握并发编程技巧,提升软件开发中的效率与性能,是Java开发者不可或缺的参考指南。
|
2天前
|
Java 数据处理 数据库
Java多线程的理解和应用场景
Java多线程的理解和应用场景
11 1
|
4天前
|
安全 Java 开发者
在多线程编程中,确保数据一致性与防止竞态条件至关重要。Java提供了多种线程同步机制
【10月更文挑战第3天】在多线程编程中,确保数据一致性与防止竞态条件至关重要。Java提供了多种线程同步机制,如`synchronized`关键字、`Lock`接口及其实现类(如`ReentrantLock`),还有原子变量(如`AtomicInteger`)。这些工具可以帮助开发者避免数据不一致、死锁和活锁等问题。通过合理选择和使用这些机制,可以有效管理并发,确保程序稳定运行。例如,`synchronized`可确保同一时间只有一个线程访问共享资源;`Lock`提供更灵活的锁定方式;原子变量则利用硬件指令实现无锁操作。
10 2