如何创建线程?Runnable和Callable的区别?

在 Java 中,创建线程有多种方式,其中最常用的是通过实现 Runnable 接口或 Callable 接口。以下详细介绍如何创建线程,以及 Runnable 和 Callable 的区别。

1. 创建线程的方式

1.1 继承 Thread 类

最原始的方式:通过继承 Thread 类并重写 run() 方法来创建线程。
示例:

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(); // 启动线程
    }
}

1.2 实现 Runnable 接口

通过实现 Runnable 接口并重写 run() 方法来创建线程。这个方式可以通过写一个私有function成员,将其放入run进行执行,做成task的形式,部分框架会使用该方式。
示例:

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

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

1.3 实现 Callable 接口

通过实现 Callable 接口并重写 call() 方法来创建线程。
Callable 可以返回结果并抛出异常。FutureTask会以该接口的实现为参数进行执行
示例:

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

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

public class Main {
    public static void main(String[] args) throws Exception {
        FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
        Thread thread = new Thread(futureTask);
        thread.start(); // 启动线程
        System.out.println(futureTask.get()); // 获取线程返回值
    }
}

1.4 使用线程池

通过线程池(如 ExecutorService)管理线程。
示例:

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

public class Main {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        executor.submit(() -> System.out.println("Thread is running"));
        executor.shutdown(); // 关闭线程池
    }
}

2. Runnable 和 Callable 的区别

特性RunnableCallable
返回值无返回值(void)有返回值(泛型类型)
异常处理不能抛出受检异常可以抛出受检异常
使用场景简单的异步任务需要返回结果或抛出异常的任务
实现方法run()call()
线程启动方式通过 Thread 或线程池提交通过 FutureTask 或线程池提交

2.1 Runnable

特点:

无返回值。
不能抛出受检异常。
示例:

Runnable task = () -> System.out.println("Running task");
new Thread(task).start();

2.2 Callable

特点:

有返回值(通过 Future 获取)。
可以抛出受检异常。
示例:

Callable<String> task = () -> {
    return "Task result";
};
Future<String> futureTask = new FutureTask<>(task);
new Thread(futureTask).start();
System.out.println(futureTask.get()); // 获取返回值

3. Future 和 FutureTask

Future:
只是一个接口定义,对于获取结果而言都是获取了FutureTask对象,然后get出来具体的返回值。

FutureTask:
实现了 Runnable 和 Future 接口。
可以包装 Callable 或 Runnable 任务。

示例

import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class Main {
    public static void main(String[] args) throws Exception {
        Callable<String> task = () -> "Task result";
        Future<String> futureTask = new FutureTask<>(task);
        new Thread(futureTask).start();
        System.out.println(futureTask.get()); // 获取返回值
    }
}

4. 总结

创建线程的方式:
继承 Thread 类。
实现 Runnable 接口。
实现 Callable 接口。
使用线程池。

Runnable 和 Callable 的区别:
Runnable 无返回值,不能抛出受检异常。
Callable 有返回值,可以抛出受检异常。

适用场景:
如果任务不需要返回结果,使用 Runnable。
如果任务需要返回结果或抛出异常,使用 Callable。
通过合理选择线程创建方式和任务接口,可以更好地满足多线程编程的需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值