Skip to content

18.2 创建线程

创建线程的方法

在 Java 中,创建线程有以下几种方法:

方法一:继承 Thread 类

步骤

  1. 继承 Thread
  2. 重写 run() 方法,在其中定义线程要执行的任务
  3. 创建线程对象并调用 start() 方法启动线程

示例

java
public class MyThread extends Thread {
    @Override
    public void run() {
        // 线程执行的任务
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " 执行: " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class ThreadCreationExample {
    public static void main(String[] args) {
        // 创建线程对象
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();
        
        // 设置线程名称
        thread1.setName("线程1");
        thread2.setName("线程2");
        
        // 启动线程
        thread1.start();
        thread2.start();
        
        // 主线程继续执行
        System.out.println(Thread.currentThread().getName() + " 执行完毕");
    }
}

方法二:实现 Runnable 接口

步骤

  1. 实现 Runnable 接口
  2. 实现 run() 方法,在其中定义线程要执行的任务
  3. 创建 Runnable 对象
  4. Runnable 对象作为参数传递给 Thread 构造函数
  5. 调用 start() 方法启动线程

示例

java
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 线程执行的任务
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " 执行: " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class RunnableCreationExample {
    public static void main(String[] args) {
        // 创建 Runnable 对象
        MyRunnable runnable = new MyRunnable();
        
        // 创建线程对象
        Thread thread1 = new Thread(runnable, "线程1");
        Thread thread2 = new Thread(runnable, "线程2");
        
        // 启动线程
        thread1.start();
        thread2.start();
        
        // 主线程继续执行
        System.out.println(Thread.currentThread().getName() + " 执行完毕");
    }
}

方法三:使用 Lambda 表达式

步骤

  1. 使用 Lambda 表达式实现 Runnable 接口
  2. 将 Lambda 表达式作为参数传递给 Thread 构造函数
  3. 调用 start() 方法启动线程

示例

java
public class LambdaThreadExample {
    public static void main(String[] args) {
        // 使用 Lambda 表达式创建线程
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + " 执行: " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "线程1");
        
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + " 执行: " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "线程2");
        
        // 启动线程
        thread1.start();
        thread2.start();
        
        // 主线程继续执行
        System.out.println(Thread.currentThread().getName() + " 执行完毕");
    }
}

方法四:使用 Callable 和 Future

步骤

  1. 实现 Callable 接口,泛型参数指定返回值类型
  2. 实现 call() 方法,在其中定义线程要执行的任务并返回结果
  3. 创建 Callable 对象
  4. 创建 ExecutorService 对象
  5. 使用 submit() 方法提交 Callable 对象,返回 Future 对象
  6. 使用 get() 方法获取线程执行结果
  7. 关闭 ExecutorService

示例

java
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableExample implements Callable<Integer> {
    private int start;
    private int end;
    
    public CallableExample(int start, int end) {
        this.start = start;
        this.end = end;
    }
    
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = start; i <= end; i++) {
            sum += i;
        }
        System.out.println(Thread.currentThread().getName() + " 计算: " + start + " 到 " + end + " 的和为 " + sum);
        return sum;
    }
}

public class CallableThreadExample {
    public static void main(String[] args) {
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(2);
        
        // 创建 Callable 对象
        Callable<Integer> task1 = new CallableExample(1, 100);
        Callable<Integer> task2 = new CallableExample(101, 200);
        
        // 提交任务
        Future<Integer> future1 = executor.submit(task1);
        Future<Integer> future2 = executor.submit(task2);
        
        try {
            // 获取结果
            int result1 = future1.get();
            int result2 = future2.get();
            System.out.println("总结果: " + (result1 + result2));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭线程池
            executor.shutdown();
        }
    }
}

继承 Thread vs 实现 Runnable

特性继承 Thread实现 Runnable
代码结构简单直接更加灵活
继承限制只能继承一个类,不能再继承其他类可以实现多个接口,还可以继承其他类
资源共享每个线程有自己的实例,资源不共享多个线程可以共享同一个 Runnable 实例
推荐使用简单场景复杂场景,推荐使用

示例:资源共享

实现 Runnable 接口实现资源共享

java
public class ResourceSharingExample implements Runnable {
    private int count = 0;
    
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            count++;
            System.out.println(Thread.currentThread().getName() + " 执行,count = " + count);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class ResourceSharingDemo {
    public static void main(String[] args) {
        // 创建一个 Runnable 实例
        ResourceSharingExample runnable = new ResourceSharingExample();
        
        // 创建两个线程,共享同一个 Runnable 实例
        Thread thread1 = new Thread(runnable, "线程1");
        Thread thread2 = new Thread(runnable, "线程2");
        
        // 启动线程
        thread1.start();
        thread2.start();
    }
}

继承 Thread 类实现资源共享

java
public class ThreadResourceSharing extends Thread {
    private static int count = 0; // 使用静态变量实现共享
    
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            count++;
            System.out.println(Thread.currentThread().getName() + " 执行,count = " + count);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class ThreadResourceSharingDemo {
    public static void main(String[] args) {
        // 创建两个线程
        ThreadResourceSharing thread1 = new ThreadResourceSharing();
        ThreadResourceSharing thread2 = new ThreadResourceSharing();
        
        // 设置线程名称
        thread1.setName("线程1");
        thread2.setName("线程2");
        
        // 启动线程
        thread1.start();
        thread2.start();
    }
}

线程池

线程池是一种管理线程的机制,它可以重用线程,减少线程创建和销毁的开销。

线程池的优势

  1. 减少线程创建和销毁的开销:线程可以重用
  2. 控制线程数量:避免线程过多导致系统资源耗尽
  3. 提高响应速度:线程池中的线程可以立即执行任务
  4. 管理线程生命周期:统一管理线程的创建、执行和销毁

使用 ExecutorService 创建线程池

java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);
        
        // 提交任务
        for (int i = 1; i <= 5; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println(Thread.currentThread().getName() + " 执行任务 " + taskId);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " 完成任务 " + taskId);
            });
        }
        
        // 关闭线程池
        executor.shutdown();
    }
}

常见问题

1. 直接调用 run() 方法

症状:线程没有并发执行,而是串行执行

解决方案:使用 start() 方法启动线程,而不是直接调用 run() 方法

示例

java
// 错误:直接调用 run() 方法
// thread.run();

// 正确:使用 start() 方法
thread.start();

2. 多次调用 start() 方法

症状:抛出 IllegalThreadStateException

解决方案:一个线程只能启动一次,不能多次调用 start() 方法

示例

java
// 错误:多次调用 start() 方法
// thread.start();
// thread.start(); // 抛出异常

// 正确:只调用一次 start() 方法
thread.start();

3. 线程安全问题

症状:多个线程同时访问共享资源时,数据不一致

解决方案:使用同步机制,如 synchronized 关键字、Lock 接口等

示例

java
// 同步代码块
synchronized (lock) {
    // 访问共享资源
}

// 同步方法
synchronized void method() {
    // 访问共享资源
}

最佳实践

  1. 优先使用实现 Runnable 接口:更加灵活,避免单继承的限制

  2. 使用线程池:对于大量短期任务,使用线程池可以提高性能

  3. 避免直接创建线程:对于生产环境,推荐使用线程池管理线程

  4. 处理异常:在线程的 run() 方法中捕获并处理异常

  5. 设置线程名称:为线程设置有意义的名称,便于调试和监控

  6. 避免线程安全问题:对于共享资源,使用适当的同步机制

  7. 合理设置线程优先级:根据任务的重要性设置线程优先级

  8. 关闭线程池:使用完毕后关闭线程池,避免资源泄漏

总结

创建线程是 Java 并发编程的基础:

  1. 创建线程的方法

    • 继承 Thread 类
    • 实现 Runnable 接口
    • 使用 Lambda 表达式
    • 使用 Callable 和 Future
  2. 继承 Thread vs 实现 Runnable

    • 实现 Runnable 接口更加灵活,推荐使用
    • 继承 Thread 类代码更简洁
  3. 资源共享

    • 实现 Runnable 接口可以轻松实现资源共享
    • 继承 Thread 类需要使用静态变量实现资源共享
  4. 线程池

    • 重用线程,减少开销
    • 控制线程数量
    • 提高响应速度
  5. 常见问题

    • 直接调用 run() 方法
    • 多次调用 start() 方法
    • 线程安全问题

通过合理选择创建线程的方法,可以有效地实现并发编程,提高程序的性能和响应速度。

© 2026 编程马·菜鸟教程 版权所有