JAVA中创建线程的四种方式
1.继承Thread类
通过继承Thread类并重写run方法来创建线程。
/**
* @author CHB
* @version 1.0
*/
public class test01 {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start();//启动线程
}
static class MyThread extends Thread{
public void run() {
System.out.println("Thread is running");
}
}
}
优点:简单易用,适合快速实现
缺点:java不支持多重继承,类已经继承了Thread类,就不能再继承其他类
2.实现Runnable接口
通过实现Runnable接口并将其传递给Thread对象来创建线程
/**
* @author CHB
* @version 1.0
*/
public class test01 {
public static void main(String[] args) {
// MyRunnable t1 = new MyRunnable();
// Thread thread = new Thread(t1);
Thread thread = new Thread(new MyRunnable());
thread.start();//启动线程
}
static class MyRunnable implements Runnable{
public void run() {
System.out.println("Thread is running");
}
}
}
优点:适合多个线程共享同一个Runnable实例,更灵活
缺点:无法直接获取线程返回值
3.使用Callable和Future
通过实现Callable接口,可以在线程执行结束后获取返回值或抛出异常。实现Callable
接口的类需要传递给FutureTask
,然后FutureTask
可以作为Thread
的目标来启动线程。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
/**
* @author CHB
* @version 1.0
*/
public class test01 {
public static void main(String[] args) {
MyCallable myCallable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
Thread thread = new Thread(futureTask);
thread.start();
//可以获取线程执行结果
Integer res = null;
try {
res = futureTask.get();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
System.out.println("res:"+res);
}
static class MyCallable implements Callable<Integer> {
public Integer call() {
return 123;
}
}
}
//FutureTask 是 RunnableFuture 接口的实现,它结合了 Runnable 和 Future 接口的功能,允许你提交一个任务给一个线程执行,并在将来某个时刻获取任务的结果。
import java.util.concurrent.*;
/**
* @author CHB
* @version 1.0
*/
public class test01 {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<String> myCallable = () -> {
return "Task is execution";
};
Future<String> future = executor.submit(myCallable);
try {
System.out.println(future.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
// 关闭线程池
executor.shutdown();
try {
// 等待线程池关闭,最多等待1秒
if (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
// 如果线程池没有在指定时间内关闭,则强制关闭
executor.shutdownNow();
}
} catch (InterruptedException e) {
// 如果当前线程在等待过程中被中断,则重新设置中断状态
Thread.currentThread().interrupt();
}
}
}
}
第二种实现方式使用 Executors.newSingleThreadExecutor() 创建了一个单线程的线程池。使用 executor.submit(myCallable) 提交 Callable 任务到线程池,并获取 Future 对象。使用 future::run 作为线程的 Runnable 目标,这是Java 8的lambda表达式语法。在 finally 块中添加了关闭线程池的逻辑,确保资源被正确释放。
优点:可以返回结果或抛出异常,适用于需要获取线程执行结果的场景
缺点:需要处理Future对象的异常
4.使用线程池
通过使用Executor框架创建和管理线程池,提高资源利用效率和任务管理能力
import java.util.concurrent.*;
/**
* @author CHB
* @version 1.0
*/
public class test01 {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);//创建一个固定大小的线程池
for (int i = 0; i < 10; i++) {
int taskId = i;
executor.execute(()->{
System.out.println("Executing task "+taskId);
});
}
executor.shutdown();//关闭线程池
}
}
优点:高效管理大量线程,避免频繁创建和销毁线程,适用于并发任务较多的场景
缺点:需要额外的管理线程的开销