Java 中创建线程的四种方法

一、继承 Thread

  1. 声明一个继承自 java.lang.Thread 的子类,并重写 run() 方法,在方法中实现线程要执行的代码。

  2. 实例化这个子类。

  3. 调用这个子类对象的 start() 方法。

// 声明一个继承自 Thread 的子类
class MyThread extends Thread {
    // 重写 run 方法
    @Override
    public void run() {
        // 线程体
    }
}

public class ThreadDemo1 {
    public static void main(String[] args) {
        // 创建线程对象
        MyThread t1 = new MyThread();
        // 启动新线程
        t1.start();
    }
}

缺点:

  • 由于 Java 的单继承机制,无法继承其他的类,不利于功能的扩展。
  • 如果线程有执行结果是不能直接返回的。

二、实现 Runnable 接口

  1. 声明一个线程任务类,实现 Runnable 接口,并实现 run() 方法,在方法中实现线程要执行的代码。

  2. 实例化这个线程任务类,并将这个线程任务类传入线程对象 Thread 的构造器。

  3. 调用线程对象的 start() 方法启动线程。

// 声明一个类,并实现 Runnable 接口
class MyRunnable implements Runnable {
    // 实现 run() 方法
    @Override
    public void run() {
        // 线程体
        System.out.println("Runnable 线程启动了");
    }
}

public class ThreadDemo2 {
    public static void main(String[] args) {
        // 创建 MyRunnable 实例,作为线程执行体
        MyRunnable mr = new MyRunnable();
        // 创建线程对象,将 Runnable 实现类作为参数传入
        Thread t1 = new Thread(mr);
        // 启动线程,执行 run() 方法中的代码
        t1.start();
    }
}

优点: 任务类仅实现了 Runnable 接口,可继续继承或实现其他类,扩展性强。

缺点: 需要多创建一个 Runnable 对象,如果线程有执行结果,不能直接返回的。

简化写法:

// 通过实现 Runnable 接口创建线程
public class ThreadDemo2_1 {
    public static void main(String[] args) {
        // 简化成 Lambda 表达式的匿名内部类写法
        new Thread(()->{
            // 线程体
            System.out.println("Thread is running...");
        }).start();
    }
}

三、实现 Callable 接口

  1. 创建任务对象:

    • 声明一个类实现 Callable 接口,实现 call() 方法,封装要做的事和要返回的数据。

    • 实例化 Callable 对象,并将其通过 FutureTask 的构造函数封装起来。

  2. 将线程任务对象通过 Thread 的构造函数传入。

  3. 调用 Thread 对象的 start() 方法启动线程。

  4. 线程执行完毕后,通过 FutureTask 的 get() 方法获取线程任务的执行结果。

// 声明线程任务类,实现 Callable 接口,通过泛型指定线程返回的数据类型
class MyCallable implements Callable<Integer> {
    private final int number;

    public MyCallable(int number) {
        this.number = number;
    }

    // 实现 call 方法
    public Integer call() {
        // 线程体
        return number;
    }
}

public class ThreadDemo3 {
    public static void main(String[] args) {
        // 创建 Callable 实例,作为线程任务
        MyCallable c1 = new MyCallable(114514);
        // 将 Callable 实例封装为 FutureTask 线程任务对象
        FutureTask<Integer> ft1 = new FutureTask<>(c1);
        // 创建线程对象,将 FutureTask 线程任务对象作为参数传入
        Thread t1 = new Thread(ft1);
        // 启动线程,执行 call() 方法
        t1.start();

        try {
            // 通过 FutureTask 线程任务对象的 get() 方法获取执行结果
            Integer result = ft1.get();
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

优点:

  • 任务类仅实现接口,可继续继承或实现其他类,扩展性强。

  • 可在线程执行完毕后获取线程执行结果。

四、使用线程池创建线程

线程池是一种管理线程的机制,它可以预先创建一定数量的线程,当有任务需要执行时,从线程池中获取线程,任务执行完毕后线程不会被销毁,而是返回到线程池供后续任务使用,从而减少线程创建和销毁的开销。

  1. 通过 Executors 工具类创建线程池(也可以通过 ThreadPoolExecutor 直接创建,更灵活)。

  2. 向线程池提交任务(可以是 RunnableCallable 类型的任务)。

  3. 任务执行完成后,关闭线程池。

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

public class ThreadPoolDemo {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池,包含3个线程
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // 提交 Runnable 任务
        executorService.submit(() -> {
            // 线程体
            System.out.println("Runnable 任务执行中,线程名:" + Thread.currentThread().getName());
        });

        // 提交 Callable 任务
        Future<Integer> future = executorService.submit(() -> {
            // 线程体
            System.out.println("Callable 任务执行中,线程名:" + Thread.currentThread().getName());
            return 100;
        });

        // 获取 Callable 任务的执行结果
        try {
            System.out.println("Callable 任务返回结果:" + future.get());
        } catch (Exception e) {
            e.printStackTrace();
        }

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

优点:

  • 重用线程,减少线程创建和销毁的性能开销。
  • 控制线程数量,避免因线程过多导致系统资源耗尽。
  • 可以统一管理和监控线程,便于任务的调度和控制。
  • 支持提交 RunnableCallable 类型的任务,灵活性高。

缺点:

  • 线程池的参数设置需要根据实际情况调整,设置不当可能影响性能。
  • 若线程池使用不当,可能会导致任务堆积、死锁等问题。

总结

方式 优点 缺点
继承 Thread 类 编程比较简单,可直接用 Thread 类里的方法 扩展性欠佳,无法再继承其他类,也不能返回线程执行结果
实现 Runnable 接口 扩展性强,实现该接口时还能继承其他类 编程相对复杂,无法返回线程执行结果
实现 Callable 接口 扩展性强,实现该接口时还能继承其他类,且可获取线程执行结果 编程相对复杂
使用线程池创建线程 重用线程,减少性能开销;控制线程数量;支持多种任务类型;便于管理和监控 参数设置复杂;使用不当可能导致问题
posted @ 2025-08-15 02:08  小莱のこい  阅读(15)  评论(0)    收藏  举报