Java中有哪几种方式来创建线程执行任务?
1、继承Thread类:
你可以创建一个继承自Thread
类的子类,并重写run()
方法来定义线程的任务。然后,通过创建子类的对象并调用start()
方法来启动线程。
class MyThread extends Thread {
public void run() {
// 线程任务代码
}
}
MyThread thread = new MyThread();
thread.start();
总结:重写的是run方法,而不是start方法,但是占用了继承的名额,java中是单继承
2、实现Runnable接口:
你可以创建一个实现了Runnable
接口的类,实现run()
方法来定义线程的任务。然后,将Runnable
对象传递给一个Thread
对象并启动它。
class MyRunnable implements Runnable {
public void run() {
// 线程任务代码
}
}
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
总结:使用Runnable接口,实现run()方法,使用依然要用到Thread,这种方式更常用
还可以使用匿名内部类和Lambda表达式
public class Thread01 {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
public void run() {
//要执行的代码
}
});
thread.start();
}
}
public class Thread01 {
public static void main(String[] args) {
//1.第一种
Thread thread = new Thread(()-> System.out.println("要执行的代码"));
//2.第二种
Runnable runs = ()->{
System.out.println("要执行的代码");
};
Thread thread2 = new Thread(runs);
thread.start();
thread2.start();
}
}
3、使用Executor框架:
Java提供了java.util.concurrent
包,其中包括Executor
框架,它允许你更灵活地管理和执行线程。你可以使用ExecutorService
接口创建线程池,并将任务提交给线程池执行。
ExecutorService executor = Executors.newFixedThreadPool(5); // 创建一个固定大小的线程池
executor.execute(new Runnable() {
public void run() {
// 线程任务代码
}
});
executor.shutdown(); // 关闭线程池
总结:实现Callable接口或者Runnable接口都可以,由ExecutorService管理线程池
4、使用Callable和Future:
与Runnable
不同,Callable
允许线程返回结果。你可以使用Callable
接口和Future
对象来执行任务并获得任务的结果。
Callable<Integer> task = new Callable<Integer>() {
public Integer call() throws Exception {
// 线程任务代码
return 42;
}
};
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(task);
Integer result = future.get(); // 获取任务结果
executor.shutdown();
使用Callable和FutureTask:
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableFutureTaskExample {
public static void main(String[] args) {
// 创建一个Callable任务
Callable<Integer> callable = new MyCallable();
// 使用FutureTask包装Callable任务
FutureTask<Integer> futureTask = new FutureTask<>(callable);
// 创建一个线程来执行FutureTask
Thread thread = new Thread(futureTask);
thread.start();
try {
// 获取任务的结果,该方法会阻塞直到任务完成
Integer result = futureTask.get();
System.out.println("Task result: " + result);
} catch (InterruptedException | ExecutionException e) {
// 处理异常
e.printStackTrace();
}
}
}
在这个示例中,我们首先创建了一个Callable
任务(MyCallable
类),然后使用FutureTask
来包装这个任务。接下来,我们创建一个线程来执行FutureTask
,然后通过get()
方法来等待任务完成并获取结果。get()
方法可能会抛出InterruptedException
和ExecutionException
异常,需要进行适当的异常处理。
使用Callable
和FutureTask
的主要优点是可以更灵活地处理任务的结果,也可以在需要时取消任务的执行。此外,FutureTask
还提供了一些其他方法,允许你查询任务的状态和取消任务的执行。这对于处理复杂的多线程场景非常有用。