Skip to main content

线程题总结

· 6 min read
Happlay71
一个渴望成为技术大佬的小白

java 开启线程有哪几种方式

在 Java 中,开启线程有多种方式,主要包括以下几种:

1. 继承 Thread

继承 Thread 类并重写 run() 方法是最基本的线程创建方式。

示例:

class MyThread extends Thread {
@Override
public void run() {
// 线程要执行的任务
System.out.println("Thread is running...");
}
}

public class ThreadExample {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 启动线程
}
}
  • 优点:代码简单,直观。
  • 缺点:无法继承其他类,因为 Java 不支持多重继承。这样会限制类的灵活性。

2. 实现 Runnable 接口

实现 Runnable 接口是 Java 中推荐的线程创建方式,尤其适用于需要实现多线程功能的类已经继承了其他类的情况。Runnable 接口只包含一个方法:run()

示例:

class MyRunnable implements Runnable {
@Override
public void run() {
// 线程要执行的任务
System.out.println("Runnable thread is running...");
}
}

public class ThreadExample {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start(); // 启动线程
}
}
  • 优点:使用更灵活,可以实现接口并继承其他类。
  • 缺点:需要通过 Thread 类来启动线程。

3. 实现 Callable 接口(适用于任务有返回值的情况)

Callable 接口是 Java 5 引入的,可以在多线程中返回结果。与 Runnable 接口不同的是,Callable 可以返回值,并且可以抛出异常。

示例:

import java.util.concurrent.*;

class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
// 线程任务,返回值
System.out.println("Callable thread is running...");
return 100;
}
}

public class ThreadExample {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable myCallable = new MyCallable();
ExecutorService executorService = Executors.newCachedThreadPool();
Future<Integer> future = executorService.submit(myCallable);
Integer result = future.get(); // 获取结果
System.out.println("Result from callable: " + result);
executorService.shutdown();
}
}
  • 优点:能够返回结果,可以处理异常。
  • 缺点:需要使用 ExecutorService 来管理线程,稍微复杂一些。

4. 使用 Lambda 表达式(适用于实现 RunnableCallable 接口)

Java 8 引入了 Lambda 表达式,允许简化线程的创建和任务的定义。

示例:

public class ThreadExample {
public static void main(String[] args) {
// 使用 Lambda 表达式创建线程
Runnable runnable = () -> System.out.println("Lambda thread is running...");
Thread thread = new Thread(runnable);
thread.start();
}
}
  • 优点:代码简洁,减少了冗余代码。
  • 缺点:仅限于 Java 8 及以上版本,且通常适用于实现简单的任务。

5. 使用 ExecutorService(线程池)

ExecutorService 提供了一种更高级的线程管理方法,允许开发者在不直接管理线程的情况下执行任务。使用线程池能有效地减少线程创建的开销,并通过线程池来复用线程。

示例:

import java.util.concurrent.*;

public class ThreadExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.submit(() -> {
// 线程任务
System.out.println("Task is running in thread pool...");
});
executorService.shutdown(); // 关闭线程池
}
}
  • 优点:提高线程的利用率,减少线程创建的开销,避免了线程过多的情况。
  • 缺点:使用线程池时需要进行一些额外的管理和配置。

6. 使用 ForkJoinPool(适用于任务分解和并行计算)

ForkJoinPool 是 Java 7 引入的一种线程池类型,专门用于处理大量的小任务,通常用于并行计算场景。它通过任务分解和合并来优化计算资源的利用。

示例:

import java.util.concurrent.*;

public class ForkJoinExample {
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool();
forkJoinPool.submit(() -> {
System.out.println("Task executed using ForkJoinPool");
});
forkJoinPool.shutdown(); // 关闭线程池
}
}
  • 优点:高效的用于大规模任务的并行计算,特别适合在 CPU 密集型任务中使用。
  • 缺点:适用于特定的场景,不是所有类型的任务都适合使用 ForkJoinPool

总结:

  1. 继承 Thread:适用于简单的线程创建,但受限于 Java 单继承的限制。
  2. 实现 Runnable 接口:适合大多数多线程任务,且可以继承其他类。
  3. 实现 Callable 接口:适合需要返回值或者处理异常的多线程任务。
  4. Lambda 表达式:简化代码,适合简单的任务创建。
  5. ExecutorService(线程池):更为高效、灵活,适合执行大量任务并复用线程。
  6. ForkJoinPool:适合并行计算任务,优化计算资源利用。

选择哪种方式取决于你的具体需求,如任务是否有返回值、是否需要线程池管理等。