第2部分-线程的创建与管理
第2部分:线程的创建与管理
核心目标
掌握线程的常见使用方式与控制手段。
1. 创建线程的3种方式
方式1:继承Thread类
基本用法
public class MyThread extends Thread {@Overridepublic void run() {System.out.println("线程执行中: " + Thread.currentThread().getName());}
}// 使用方式
public class ThreadExample1 {public static void main(String[] args) {MyThread thread = new MyThread();thread.start(); // 启动线程}
}
优缺点分析
优点:
- 代码简单直观
- 可以直接使用Thread类的方法
缺点:
- Java单继承限制,无法继承其他类
- 线程和任务耦合度高
- 不符合面向对象设计原则
方式2:实现Runnable接口
基本用法
public class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Runnable任务执行中: " + Thread.currentThread().getName());}
}// 使用方式
public class ThreadExample2 {public static void main(String[] args) {// 方式1:直接使用Thread thread1 = new Thread(new MyRunnable());thread1.start();// 方式2:使用Lambda表达式Thread thread2 = new Thread(() -> {System.out.println("Lambda任务执行中: " + Thread.currentThread().getName());});thread2.start();// 方式3:方法引用Thread thread3 = new Thread(ThreadExample2::taskMethod);thread3.start();}private static void taskMethod() {System.out.println("方法引用任务执行中: " + Thread.currentThread().getName());}
}
优缺点分析
优点:
- 可以继承其他类
- 任务和线程分离,符合单一职责原则
- 可以复用任务对象
- 支持Lambda表达式,代码简洁
缺点:
- 无法直接获取返回值
- 无法抛出受检异常
方式3:使用Callable + Future
基本用法
import java.util.concurrent.*;public class MyCallable implements Callable<String> {private final String taskName;public MyCallable(String taskName) {this.taskName = taskName;}@Overridepublic String call() throws Exception {Thread.sleep(2000); // 模拟耗时任务return "任务 " + taskName + " 执行完成";}
}public class ThreadExample3 {public static void main(String[] args) throws Exception {// 使用ExecutorServiceExecutorService executor = Executors.newSingleThreadExecutor();// 提交Callable任务Future<String> future = executor.submit(new MyCallable("测试任务"));System.out.println("任务已提交,等待结果...");// 获取结果(阻塞等待)String result = future.get();System.out.println("结果: " + result);// 关闭线程池executor.shutdown();}
}
高级用法
public class CallableAdvancedExample {public static void main(String[] args) throws Exception {ExecutorService executor = Executors.newFixedThreadPool(3);// 创建多个任务List<Callable<String>> tasks = Arrays.asList(new MyCallable("任务1"),new MyCallable("任务2"),new MyCallable("任务3"));// 方式1:invokeAll - 等待所有任务完成List<Future<String>> futures = executor.invokeAll(tasks);for (Future<String> future : futures) {System.out.println("结果: " + future.get());}// 方式2:invokeAny - 等待任意一个任务完成String result = executor.invokeAny(tasks);System.out.println("最快完成的任务结果: " + result);executor.shutdown();}
}
优缺点分析
优点:
- 可以获取返回值
- 可以抛出异常
- 支持超时控制
- 支持批量任务管理
缺点:
- 代码相对复杂
- 需要管理ExecutorService
2. Thread API常用方法
start()方法
public class StartExample {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("线程开始执行");});// 启动线程thread.start();// 注意:不能重复调用start()// thread.start(); // 会抛出IllegalThreadStateException}
}
join()方法
public class JoinExample {public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(() -> {try {Thread.sleep(2000);System.out.println("线程1执行完成");} catch (InterruptedException e) {Thread.currentThread().interrupt();}});Thread thread2 = new Thread(() -> {try {Thread.sleep(1000);System.out.println("线程2执行完成");} catch (InterruptedException e) {Thread.currentThread().interrupt();}});thread1.start();thread2.start();// 等待thread1完成thread1.join();System.out.println("thread1已完成,继续执行主线程");// 等待thread2完成,最多等待3秒thread2.join(3000);System.out.println("主线程执行完成");}
}
interrupt()方法
public class InterruptExample {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {try {Thread.sleep(1000);System.out.println("线程运行中...");} catch (InterruptedException e) {// 捕获中断异常,重新设置中断标志Thread.currentThread().interrupt();System.out.println("线程被中断");break;}}});thread.start();// 3秒后中断线程Thread.sleep(3000);thread.interrupt();// 等待线程结束thread.join();System.out.println("主线程结束");}
}
其他常用方法
public class ThreadMethodsExample {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("线程执行中...");});// 设置线程名称thread.setName("MyThread");// 设置优先级(1-10)thread.setPriority(Thread.MAX_PRIORITY);// 设置为守护线程thread.setDaemon(true);// 获取线程信息System.out.println("线程名称: " + thread.getName());System.out.println("线程优先级: " + thread.getPriority());System.out.println("是否守护线程: " + thread.isDaemon());System.out.println("线程状态: " + thread.getState());System.out.println("是否存活: " + thread.isAlive());thread.start();}
}
3. 守护线程与用户线程
守护线程(Daemon Thread)
- 定义:为其他线程提供服务的线程
- 特点:
- 当所有用户线程结束时,守护线程会自动结束
- 不能执行重要的业务逻辑
- 通常用于垃圾回收、监控等后台任务
用户线程(User Thread)
- 定义:执行用户任务的线程
- 特点:
- JVM会等待所有用户线程结束后才退出
- 可以执行重要的业务逻辑
- 默认创建的线程都是用户线程
示例代码
public class DaemonThreadExample {public static void main(String[] args) throws InterruptedException {// 创建守护线程Thread daemonThread = new Thread(() -> {while (true) {try {Thread.sleep(1000);System.out.println("守护线程运行中...");} catch (InterruptedException e) {Thread.currentThread().interrupt();break;}}});daemonThread.setDaemon(true);daemonThread.start();// 创建用户线程Thread userThread = new Thread(() -> {try {Thread.sleep(3000);System.out.println("用户线程执行完成");} catch (InterruptedException e) {Thread.currentThread().interrupt();}});userThread.start();// 等待用户线程完成userThread.join();System.out.println("主线程结束,JVM将退出");// 此时守护线程也会自动结束}
}
4. 线程优先级与调度策略
线程优先级
public class PriorityExample {public static void main(String[] args) {// 创建不同优先级的线程for (int i = 1; i <= 5; i++) {Thread thread = new Thread(() -> {for (int j = 0; j < 1000; j++) {// 模拟CPU密集型任务Math.random();}System.out.println(Thread.currentThread().getName() + " 完成");});thread.setName("Thread-" + i);thread.setPriority(i * 2); // 优先级:2, 4, 6, 8, 10thread.start();}}
}
优先级常量
public class PriorityConstants {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("线程执行中");});// 使用常量设置优先级thread.setPriority(Thread.MIN_PRIORITY); // 1thread.setPriority(Thread.NORM_PRIORITY); // 5thread.setPriority(Thread.MAX_PRIORITY); // 10// 获取当前线程优先级int priority = Thread.currentThread().getPriority();System.out.println("当前线程优先级: " + priority);}
}
注意事项
- 优先级只是建议,不保证执行顺序
- 不同操作系统对优先级的处理可能不同
- 过度依赖优先级可能导致线程饥饿
- 现代JVM通常忽略优先级设置
5. 异常处理与线程中断机制
线程异常处理
public class ThreadExceptionExample {public static void main(String[] args) {// 设置未捕获异常处理器Thread.setDefaultUncaughtExceptionHandler((thread, exception) -> {System.out.println("线程 " + thread.getName() + " 发生异常: " + exception.getMessage());});Thread thread = new Thread(() -> {throw new RuntimeException("线程内部异常");});thread.start();try {thread.join();} catch (InterruptedException e) {Thread.currentThread().interrupt();}}
}
自定义异常处理器
public class CustomExceptionHandler implements Thread.UncaughtExceptionHandler {@Overridepublic void uncaughtException(Thread thread, Throwable exception) {System.out.println("线程 " + thread.getName() + " 发生异常:");exception.printStackTrace();// 可以在这里进行日志记录、告警等操作// 例如:发送邮件、写入日志文件等}
}public class CustomHandlerExample {public static void main(String[] args) {Thread thread = new Thread(() -> {throw new RuntimeException("自定义异常");});thread.setUncaughtExceptionHandler(new CustomExceptionHandler());thread.start();}
}
线程中断机制详解
public class InterruptMechanismExample {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {// 方式1:检查中断标志while (!Thread.currentThread().isInterrupted()) {System.out.println("线程运行中...");try {Thread.sleep(1000);} catch (InterruptedException e) {// 方式2:捕获InterruptedExceptionSystem.out.println("线程被中断,退出循环");Thread.currentThread().interrupt(); // 重新设置中断标志break;}}});thread.start();// 3秒后中断线程Thread.sleep(3000);thread.interrupt();thread.join();System.out.println("主线程结束");}
}
中断状态检查
public class InterruptStatusExample {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {// 检查中断状态if (Thread.currentThread().isInterrupted()) {System.out.println("线程已被中断");return;}// 执行任务for (int i = 0; i < 10; i++) {if (Thread.currentThread().isInterrupted()) {System.out.println("任务执行过程中被中断");break;}System.out.println("执行任务 " + i);try {Thread.sleep(500);} catch (InterruptedException e) {System.out.println("睡眠时被中断");Thread.currentThread().interrupt();break;}}});thread.start();// 立即中断线程thread.interrupt();thread.join();}
}
实践练习
练习1:多线程计算
public class MultiThreadCalculation {public static void main(String[] args) throws InterruptedException {int[] numbers = IntStream.range(1, 1000001).toArray();int threadCount = 4;int chunkSize = numbers.length / threadCount;List<Thread> threads = new ArrayList<>();List<Long> results = Collections.synchronizedList(new ArrayList<>());for (int i = 0; i < threadCount; i++) {final int start = i * chunkSize;final int end = (i == threadCount - 1) ? numbers.length : (i + 1) * chunkSize;Thread thread = new Thread(() -> {long sum = 0;for (int j = start; j < end; j++) {sum += numbers[j];}results.add(sum);System.out.println("线程 " + Thread.currentThread().getName() + " 计算完成: " + sum);});thread.setName("Calculator-" + i);threads.add(thread);thread.start();}// 等待所有线程完成for (Thread thread : threads) {thread.join();}// 汇总结果long totalSum = results.stream().mapToLong(Long::longValue).sum();System.out.println("总和: " + totalSum);}
}
练习2:线程池任务管理
public class ThreadPoolTaskExample {public static void main(String[] args) throws Exception {ExecutorService executor = Executors.newFixedThreadPool(3);List<Future<String>> futures = new ArrayList<>();// 提交多个任务for (int i = 0; i < 5; i++) {final int taskId = i;Future<String> future = executor.submit(() -> {Thread.sleep(1000 + taskId * 500);return "任务 " + taskId + " 完成";});futures.add(future);}// 获取结果for (Future<String> future : futures) {try {String result = future.get(2, TimeUnit.SECONDS);System.out.println("结果: " + result);} catch (TimeoutException e) {System.out.println("任务超时,取消执行");future.cancel(true);}}executor.shutdown();}
}
总结
本部分详细介绍了Java线程的创建与管理:
- 三种创建方式:继承Thread、实现Runnable、使用Callable+Future
- Thread API:start()、join()、interrupt()等核心方法
- 线程类型:守护线程与用户线程的区别和使用场景
- 优先级调度:线程优先级设置和注意事项
- 异常处理:线程异常处理机制和最佳实践
- 中断机制:线程中断的正确使用方式
掌握这些基础知识后,下一部分将学习线程同步与通信机制。