编程自学指南:java程序设计开发,多线程编程
学习目标:
-  理解进程与线程的核心概念及区别 
-  掌握Java中线程的创建与生命周期管理 
-  能够通过同步机制解决线程安全问题 
-  使用线程池优化多线程程序性能 
一、课程引入
1.1 为什么需要多线程?
-  应用场景: -  提高程序响应速度(如GUI界面后台任务) 
-  充分利用多核CPU资源 
-  实现异步处理(如文件下载、网络请求) 
 
-  
-  生活类比: -  进程:银行营业厅(独立资源单位) 
-  线程:银行窗口(共享进程资源,并发处理任务) 
 
-  
二、线程的创建与启动
2.1 继承Thread类
案例1:简单线程执行
public class MyThread extends Thread {  @Override  public void run() {  System.out.println("线程执行:" + Thread.currentThread().getName());  }  
}  // 启动线程  
MyThread thread = new MyThread();  
thread.start();  // 输出:线程执行:Thread-02.2 实现Runnable接口(推荐)
案例2:多窗口售票系统
public class Ticket implements Runnable {  private int tickets = 10;  @Override  public void run() {  while (tickets > 0) {  System.out.println(Thread.currentThread().getName() + "售出票号:" + tickets--);  }  }  
}  // 启动三个窗口  
Thread t1 = new Thread(new Ticket(), "窗口1");  
Thread t2 = new Thread(new Ticket(), "窗口2");  
t1.start();  
t2.start();  
// 注意:此处存在线程安全问题(后续解决)三、线程同步与锁机制
3.1 synchronized关键字
案例3:解决售票超卖问题
public class SafeTicket implements Runnable {  private int tickets = 10;  @Override  public void run() {  while (true) {  synchronized (this) {  // 同步代码块  if (tickets > 0) {  System.out.println(Thread.currentThread().getName() + "售出票号:" + tickets--);  } else {  break;  }  }  }  }  
}3.2 Lock接口(ReentrantLock)
案例4:使用Lock实现同步
private Lock lock = new ReentrantLock();  public void run() {  while (true) {  lock.lock();  try {  if (tickets > 0) {  System.out.println(Thread.currentThread().getName() + "售出票号:" + tickets--);  } else {  break;  }  } finally {  lock.unlock();  }  }  
}3.3 volatile关键字
-  作用:确保变量可见性,禁止指令重排序 
private volatile boolean running = true;  public void run() {  while (running) {  // 执行任务  }  
}  public void stop() {  running = false;  
}四、线程池
4.1 Executor框架
案例5:使用线程池执行任务
ExecutorService pool = Executors.newFixedThreadPool(3);  
for (int i = 0; i < 10; i++) {  pool.execute(() -> {  System.out.println(Thread.currentThread().getName() + "执行任务");  });  
}  
pool.shutdown();4.2 Callable与Future
案例6:获取异步计算结果
Callable<Integer> task = () -> {  Thread.sleep(1000);  return 1 + 1;  
};  ExecutorService pool = Executors.newSingleThreadExecutor();  
Future<Integer> future = pool.submit(task);  
System.out.println("计算结果:" + future.get());  // 阻塞直到结果返回  
pool.shutdown(); 五、综合应用
5.1 案例7:生产者-消费者模型
public class MessageQueue {  private Queue<String> queue = new LinkedList<>();  private int capacity = 5;  public synchronized void produce(String msg) throws InterruptedException {  while (queue.size() == capacity) {  wait();  // 队列满时等待  }  queue.offer(msg);  notifyAll();  // 唤醒消费者  }  public synchronized String consume() throws InterruptedException {  while (queue.isEmpty()) {  wait();  // 队列空时等待  }  String msg = queue.poll();  notifyAll();  // 唤醒生产者  return msg;  }  
}六、常见问题与最佳实践
6.1 常见错误
-  错误1:直接调用run()方法 thread.run(); // 错误:不会启动新线程,仍在主线程执行
-   错误2:锁对象选择不当 synchronized (new Object()) { ... } // 锁无效!
6.2 最佳实践
-  优先实现Runnable接口:避免单继承限制 
-  使用线程池代替手动创建线程:资源可控,避免频繁创建销毁开销 
-  避免死锁:按固定顺序获取多个锁 
七、总结与练习
7.1 总结
-  线程创建:继承Thread vs 实现Runnable/Callable 
-  线程同步:synchronized、Lock、volatile 
-  线程池:Executor框架管理线程生命周期 
7.2 课后任务
-  实现一个多线程下载器(模拟分块下载文件) 
-  用线程池优化案例2的售票系统 
-  预习下一节课:网络编程基础 
7.3 扩展挑战
-  用 CompletableFuture实现异步任务链(如先查询用户信息,再查询订单)
