Java提供了多种创建线程的方法:
- 集成Thread类
- 实现Runnable接口
- 通过Callable和Future创建线程
继承Thread类
Thread
类是一个线程类,其定义了所有与线程相关的功能,只有这个类才能开启任务,才会被CPU单独去执行。
实现步骤
- 定义一个类继承Thread类
- 重写run(),添加自己的任务
- 创建实例对象
- 调用**start()**启动线程
代码实例
// 继承Thread类,使得MyThread具备所有与线程相关的功能
class MyThread extends Thread {
// 重写run方法,添加自己的任务实现
@Override
public void run() {
// @TODO 执行任务
}
}
public class Main {
public static void main(String[] args) {
// 创建实例
MyThread myThread = new MyThread();
// 启动线程
myThread.start();
}
}
还可通过匿名类来简化创建
// 方式一
Thread 变量名 = new Thread() {
@Override
public void run() {
// @TODO 执行任务
}
};
// 启动线程
变量名.start();
// 方式二
new Thread() {
@Override
public void run() {
// @TODO 执行任务
}
}.start();
实现Runnable接口
Runnable
接口用来描述线程将要执行的任务,它的实现类是线程执行的任务,而不是线程对象。即Runnable实现对象是线程任务对象,而不是线程对象,其必须绑定到Thread对象中,通过执行start()
,就会自动执行其**run()**中定义的任务。
Runnable是一个函数式接口
package java.lang;
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
实现步骤
- 定义一个类实现Runnable接口
- 重写run(),添加自己的任务
- 创建接口实现对象
- 创建Thread对象,将接口实现对象作为Thread构造方法的参数
- 调用**start()**启动线程
代码实例
// 实现Runnable接口,使得MyRunnable具备所有与线程相关的功能
class MyRunnable implements Runnable {
@Override
public void run() {
// @TODO 执行任务
}
}
public class Main {
public static void main(String[] args) {
// 创建接口实现对象
MyRunnable myRunnable = new MyRunnable();
// 创建线程,将接口实现类作为构造方法的参数
Thread thread = new Thread(myRunnable);
// 启动线程
thread.start();
}
}
还可通过匿名类或Lambda表达式来简化实现
// 方式一(匿名类)
Thread 变量 = new Thread(new Runnable() {
@Override
public void run() {
// @TODO 执行任务
}
});
// 启动线程
变量.start();
// 方式二(匿名类)
new Thread(new Runnable() {
@Override
public void run() {
// @TODO 执行任务
}
}).start();
// 方式三(Lambda表达式)
Thread 变量 = new Thread(() -> {
// @TODO 执行任务
});
// 启动线程
变量.start();
// 方式四(Lambda表达式)
new Thread(new Runnable() {
// @TODO 执行任务
}).start();
通过Callable和Future创建线程
Callable
接口类似于Runnable,与Runnable不同的是,Callable有返回值且可以抛出异常。
使用Callable
接口中的call()可以有返回值并且能够申明抛出异常。但是其需要配合FutureTask或线程池来使用。
Callable是一个函数式接口
package java.util.concurrent;
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
实现步骤
- 定义一个类实现
java.util.concurrent
包下的Callable接口 - 重写call(),添加自己的任务
- 创建FutureTask对象,将接口实现对象作为FutureTask构造方法的参数
- 创建Thread线程对象,将FutureTask对象作为Thread构造方法的参数
- 调用**start()**启动线程
- 调用FutureTask的**get()**获取结果
代码实例
// 实现Callable<V>接口,使得MyRunnable具备所有与线程相关的功能
class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
// @TODO 执行任务
return "结束";
}
}
public class Main {
public static void main(String[] args) {
// 创建Callable实现类对象
MyCallable myCallable = new MyCallable();
// 创建FutureTask对象
FutureTask futureTask = new FutureTask<>(myCallable);
// 创建Thread对象
Thread thread = new Thread(futureTask);
thread.start();
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
}
Future
Future
表示异步任务的结果,可以用来等待任务执行完成并获得结果和取消任务。
package java.util.concurrent;
public interface Future<V> {
/**
* 取消任务,取消任务可能会存在3种可能
* 1. 任务已经完成、已被取消或由于其他原因无法取消,则返回false
* 2. 任务还未启动,则该任务不会被执行,返回true
* 3. 任务已经启动,mayInterruptIfRunning值确定是否应中断执行此任务的线程以尝试停止该任务
*/
boolean cancel(boolean mayInterruptIfRunning);
/**
* 任务在完成前是否被取消
*/
boolean isCancelled();
/**
* 任务是否完成
*/
boolean isDone();
/**
* 获取任务执行结果
*/
V get() throws InterruptedException, ExecutionException;
/**
* 在给定时间内获取任务执行结果,超过时间抛出异常
*/
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
Future类图结构
总结
- 继承的方式适用于一个任务仅被一个线程对象执行的情况。有异常只能在内部处理,不能向上抛出
- 实现Runnable接口方式适用于一个任务被多个线程对象执行的情况。有异常只能在内部处理,不能向上抛出
- 实现Callable接口方式适用于一个任务被多个线程执行的情况,同时还可获得任务的执行结果。有异常可在内部处理,也可向上抛出