1.1 线程在Java编程中的重要性
想象一下你在餐厅同时接待多桌客人。如果只能一桌一桌服务,后面的顾客可能要等很久。Java线程就像餐厅里的多个服务员,让程序能够"同时"处理多个任务。现代应用几乎都离不开多线程——从网页的异步加载到后台数据处理,线程让程序变得更高效、更响应。
我记得第一次写网络爬虫时,单线程下载几十个页面花了近十分钟。引入多线程后,同样的任务两分钟就完成了。这种效率提升是实实在在的,特别是在如今多核处理器普及的环境下,合理使用线程能充分发挥硬件性能。
1.2 Java优学网线程教程特色介绍
我们的教程有个明显特点:注重实战。很多概念通过具体场景来理解会更深刻。比如讲解线程安全时,我们会模拟银行转账的经典案例,让你看到数据竞争如何发生,又该如何避免。
另一个特色是渐进式学习路径。从最简单的线程创建开始,逐步深入到线程池、并发容器等高级主题。每个知识点都配有可运行的代码示例,你可以直接复制到IDE里测试效果。这种边学边练的方式,对掌握多线程编程特别有帮助。
1.3 线程创建方法概览
Java提供了多种创建线程的方式,就像工具箱里有不同用途的工具。最基础的是继承Thread类,这种方式直观易懂,适合初学者理解线程的基本概念。
实现Runnable接口是更灵活的方案,它让线程任务与线程本身分离,符合面向接口编程的思想。很多开发者更偏爱这种方式,因为它避免了Java单继承的限制。
对于需要返回结果的场景,Callable和Future组合提供了完美的解决方案。而在线程池中管理线程,则是现代Java应用的首选方案,它能有效控制资源消耗,提升系统稳定性。
这些方法各有适用场景,没有绝对的优劣。关键在于理解它们的特点,根据具体需求选择最合适的工具。接下来的章节会详细探讨每种方法的实现细节和使用技巧。 class PrintOddThread extends Thread {
@Override
public void run() {
for (int i = 1; i <= 10; i += 2) {
System.out.println("奇数: " + i);
}
}
}
class PrintEvenThread extends Thread {
@Override
public void run() {
for (int i = 2; i <= 10; i += 2) {
System.out.println("偶数: " + i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
PrintOddThread t1 = new PrintOddThread();
PrintEvenThread t2 = new PrintEvenThread();
t1.start();
t2.start();
}
}
class InventoryTask implements Runnable {
private String productId;
private int quantity;
public InventoryTask(String productId, int quantity) {
this.productId = productId;
this.quantity = quantity;
}
@Override
public void run() {
// 模拟库存扣减操作
System.out.println(Thread.currentThread().getName() +
" 正在处理商品 " + productId +
" 的库存扣减,数量: " + quantity);
// 实际的库存扣减逻辑...
}
}
public class InventorySystem {
public static void main(String[] args) {
// 创建多个库存处理任务
InventoryTask task1 = new InventoryTask("P001", 2);
InventoryTask task2 = new InventoryTask("P002", 1);
InventoryTask task3 = new InventoryTask("P003", 5);
// 使用不同的线程执行这些任务
Thread t1 = new Thread(task1, "库存线程-1");
Thread t2 = new Thread(task2, "库存线程-2");
Thread t3 = new Thread(task3, "库存线程-3");
t1.start();
t2.start();
t3.start();
}
}
class DataProcessor implements Callable
private String data;
public DataProcessor(String data) {
this.data = data;
}
@Override
public Integer call() throws Exception {
if (data == null) {
throw new IllegalArgumentException("数据不能为空");
}
// 模拟数据处理,返回处理后的记录数
Thread.sleep(1000); // 模拟耗时操作
return data.length();
}
}
public class CallableExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
// 提交任务
Future<Integer> future1 = executor.submit(new DataProcessor("测试数据"));
Future<Integer> future2 = executor.submit(new DataProcessor(null));
try {
// 获取第一个任务的结果
Integer result1 = future1.get();
System.out.println("第一个任务处理结果: " + result1);
// 第二个任务会抛出异常
Integer result2 = future2.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("任务被中断");
} catch (ExecutionException e) {
System.out.println("任务执行异常: " + e.getCause().getMessage());
} finally {
executor.shutdown();
}
}
}
// 自定义线程池配置 ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
60L, // 空闲线程存活时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(100), // 工作队列
Executors.defaultThreadFactory(), // 线程工厂
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);