基础使用

创建线程

  1. 继承 Thread 类,重写 run()
代码块JAVA · 13 行收起展开
  class MyThread extends Thread {
      @Override
      public void run() {
          System.out.println("线程执行: " + Thread.currentThread().getName());
      }
  }
  // 使用
  public class Main {
      public static void main(String[] args) {
          MyThread t = new MyThread();
          t.start();   // 注意!是 start() 不是 run()
      }
  }

关键坑:调 start() 才会开新线程;直接调 run()
只是普通方法调用,还在主线程里跑,不会开新线程。

缺点:Java 单继承,继承了 Thread 就不能再继承别的类,太占用继承名额。


  1. 实现 Runnable 接口(最推荐的传统写法)
代码块JAVA · 15 行收起展开
  class MyTask implements Runnable {
      @Override
      public void run() {
          System.out.println("任务执行: " + Thread.currentThread().getName());
      }
  }

  // 使用
  public class Main {
      public static void main(String[] args) {
          MyTask task = new MyTask();
          Thread t = new Thread(task);  // 把任务交给 Thread
          t.start();
      }
  }

为什么比继承 Thread 好:

  • 只是实现接口,不占继承名额,类还能继承别的
  • 任务和线程分离 —— 任务(Runable)负责”干什么”,线程(Thread)负责”怎么跑”,职责清晰
  • 同一个 Runnable 可以交给多个线程,或丢给线程池

Lambda 简写

代码块JAVA · 4 行收起展开
  Thread t = new Thread(() -> {
      System.out.println("Lambda 任务");
  });
  t.start();

  1. 实现 Callable + FutureTask(能拿返回值 / 抛异常)

前两种的 run() 返回 void,拿不到结果也不能抛检查异常。Callable 补上这个缺口。

代码块JAVA · 22 行收起展开
  import java.util.concurrent.*;

  class MyCallable implements Callable<Integer> {
      @Override
      public Integer call() throws Exception {   // 有返回值,还能抛异常
          Thread.sleep(1000);
          return 42;
      }
  }

  // 使用
  public class Main {
      public static void main(String[] args) throws Exception {
          // FutureTask 包装 Callable,它本身是 Runnable,能塞给 Thread
          FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());
          Thread t = new Thread(futureTask);
          t.start();

          Integer result = futureTask.get();  // 阻塞等待结果
          System.out.println("结果: " + result);  // 42
      }
  }

对照记忆:

Runnable → run() → 返回 void,不能抛检查异常
Callable → call() → 有返回值,能抛异常


  1. 线程池(实际开发唯一推荐)

前面三种都是手动 new Thread,实际开发几乎不这么干 ——
频繁创建销毁线程开销大,还可能无限创建撑爆内存。生产环境统一用线程池。

代码块JAVA · 27 行收起展开
  import java.util.concurrent.*;

  public class Main {
      public static void main(String[] args) {
          // 阿里规范:手动 new,不用 Executors 的快捷方法(防无界队列 OOM)
          ExecutorService pool = new ThreadPoolExecutor(
              2,                          // 核心线程数
              4,                          // 最大线程数
              60L, TimeUnit.SECONDS,      // 空闲线程存活时间
              new ArrayBlockingQueue<>(10) // 有界任务队列
          );

          // 提交 Runnable(无返回值)
          pool.execute(() -> System.out.println("execute 任务"));

          // 提交 Callable(有返回值)
          Future<Integer> future = pool.submit(() -> 100);

          try {
              System.out.println("结果: " + future.get());
          } catch (Exception e) {
              e.printStackTrace();
          } finally {
              pool.shutdown();  // 用完记得关
          }
      }
  }

“为什么不用 Executors.newFixedThreadPool()”,
答:Executors 的快捷方法底层用无界队列(LinkedBlockingQueue,容量
Integer.MAX_VALUE),任务堆积会 OOM;newCachedThreadPool 最大线程数是
▎ Integer.MAX_VALUE,可能创建海量线程。所以《阿里巴 Java 开发手册》强制要求手动 new
▎ ThreadPoolExecutor,参数自己控制。


  1. 现代补充:CompletableFuture / 虚拟线程

不是”创建线程的基础方式”,但现代 Java 常用,提一嘴显得跟得上版本。

代码块JAVA · 17 行收起展开
  CompletableFuture(异步编排):

  CompletableFuture.supplyAsync(() -> 42)
      .thenApply(x -> x * 2)
      .thenAccept(System.out::println);  // 输出 84

  虚拟线程(JDK21 正式发布,轻量级线程,能开百万个):

  // JDK21+
  Thread.startVirtualThread(() -> {
      System.out.println("虚拟线程");
  });

  // 或用虚拟线程池
  try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
      executor.submit(() -> System.out.println("虚拟线程任务"));
  }

延伸阅读