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 编程马·菜鸟教程 版权所有