一课掌握Java并发编程精髓(完结13章)

jintianzhousan · · 29 次点击 · · 开始浏览    
获课:666it.top/6121/ Java并发编程基石:线程生命周期与同步锁终极指南 一、线程生命周期详解 Java线程的生命周期是理解并发编程的基础,它由以下几个关键状态组成: 1. 线程状态全览 NEW(新建状态):通过new Thread()创建线程对象但尚未调用start()方法时的状态 RUNNABLE(可运行/运行状态):调用start()方法后进入的状态,包括就绪和运行中两种情况 BLOCKED(阻塞状态):线程试图获取对象锁而该锁被其他线程持有时的状态 WAITING(无限等待状态):线程等待其他线程执行特定操作(如Object.wait()或Thread.join()) TIMED_WAITING(定时等待状态):线程等待特定时间(如Thread.sleep(long)) TERMINATED(终止状态):线程执行完毕或异常退出的状态 2. 状态转换示例代码 Java  public class ThreadStateExample implements Runnable { public static Thread thread1; public static void main(String[] args) throws InterruptedException { thread1 = new Thread(new ThreadStateExample()); System.out.println("State after creation: " + thread1.getState()); // NEW thread1.start(); System.out.println("State after start: " + thread1.getState()); // RUNNABLE Thread.sleep(100); System.out.println("State while sleeping: " + thread1.getState()); // TIMED_WAITING thread1.join(); System.out.println("State after completion: " + thread1.getState()); // TERMINATED } @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } 二、线程创建方式 Java提供了多种创建线程的方式: 1. 继承Thread类 Java  class MyThread extends Thread { @Override public void run() { // 线程执行的代码 System.out.println("线程运行中..."); } } public class Main { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); } } 2. 实现Runnable接口 Java  class MyRunnable implements Runnable { @Override public void run() { // 线程执行的代码 } } public class Main { public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.start(); } } 三、同步锁机制详解 1. synchronized关键字 Java中最基本的同步机制,可用于方法和代码块: Java  // 同步方法 public synchronized void synchronizedMethod() { // 临界区代码 } // 同步代码块 public void someMethod() { synchronized(this) { // 临界区代码 } } 原理:synchronized会在进入代码块时自动加锁,退出时自动解锁。如果线程t1抢到了锁,其他线程将被阻塞,直到t1释放锁。 2. ReentrantLock Java提供的更灵活的锁实现: Java  import java.util.concurrent.locks.ReentrantLock; public class Counter { private final ReentrantLock lock = new ReentrantLock(); private int count = 0; public void increment() { lock.lock(); try { count++; } finally { lock.unlock(); } } } 特点: 可重入:同一线程可多次获取同一把锁 可中断:lockInterruptibly()方法允许在等待时响应中断 公平性:可选择公平或非公平锁 条件变量:支持多个条件队列 3. 读写锁(ReadWriteLock) 适用于读多写少的场景: Java  import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteCache { private final ReadWriteLock rwLock = new ReentrantReadWriteLock(); private Map<String, Object> cache = new HashMap<>(); public Object get(String key) { rwLock.readLock().lock(); try { return cache.get(key); } finally { rwLock.readLock().unlock(); } } public void put(String key, Object value) { rwLock.writeLock().lock(); try { cache.put(key, value); } finally { rwLock.writeLock().unlock(); } } } 4. StampedLock(Java8+) 提供乐观读锁机制,在读多写少场景下性能更优: Java  import java.util.concurrent.locks.StampedLock; public class Point { private double x, y; private final StampedLock sl = new StampedLock(); // 写锁示例 public void move(double deltaX, double deltaY) { long stamp = sl.writeLock(); try { x += deltaX; y += deltaY; } finally { sl.unlockWrite(stamp); } } // 乐观读示例 public double distanceFromOrigin() { long stamp = sl.tryOptimisticRead(); double currentX = x, currentY = y; if (!sl.validate(stamp)) { stamp = sl.readLock(); try { currentX = x; currentY = y; } finally { sl.unlockRead(stamp); } } return Math.sqrt(currentX * currentX + currentY * currentY); } } 四、高级同步工具 1. Semaphore(信号量) 控制同时访问特定资源的线程数量: Java  import java.util.concurrent.Semaphore; public class Pool { private static final int MAX_AVAILABLE = 10; private final Semaphore available = new Semaphore(MAX_AVAILABLE, true); public Object getItem() throws InterruptedException { available.acquire(); return getNextAvailableItem(); } public void putItem(Object x) { if (markAsUnused(x)) available.release(); } // 实现细节省略... } 2. CountDownLatch 允许一个或多个线程等待其他线程完成操作: Java  import java.util.concurrent.CountDownLatch; public class Worker implements Runnable { private final CountDownLatch startSignal; private final CountDownLatch doneSignal; Worker(CountDownLatch startSignal, CountDownLatch doneSignal) { this.startSignal = startSignal; this.doneSignal = doneSignal; } public void run() { try { startSignal.await(); doWork(); doneSignal.countDown(); } catch (InterruptedException ex) {} // 返回 } void doWork() { /* ... */ } } 3. CyclicBarrier 让一组线程互相等待,直到所有线程都到达某个屏障点: Java  import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class Solver { final int N; final float[][] data; final CyclicBarrier barrier; class Worker implements Runnable { int myRow; Worker(int row) { myRow = row; } public void run() { while (!done()) { processRow(myRow); try { barrier.await(); } catch (InterruptedException | BrokenBarrierException ex) { return; } } } } public Solver(float[][] matrix) { data = matrix; N = matrix.length; barrier = new CyclicBarrier(N, () -> mergeRows(...)); // 创建并启动线程 } } 五、死锁问题与预防 1. 死锁产生的四个必要条件 互斥条件:资源一次只能由一个线程占用 请求与保持条件:线程持有至少一个资源,并等待获取其他资源 不剥夺条件:已分配给线程的资源,不能被其他线程强行夺取 循环等待条件:存在一个线程等待的循环链 2. 死锁预防策略 避免嵌套锁:尽量不要在持有一个锁的同时去获取另一个锁 锁排序:确保所有线程以相同的顺序获取锁 锁超时:使用tryLock()设置超时时间 死锁检测:实现或使用现有的死锁检测机制 Java  // 使用tryLock避免死锁示例 public boolean transferMoney(Account from, Account to, long amount, long timeout) { long stopTime = System.nanoTime() + timeout; while (true) { if (from.lock.tryLock()) { try { if (to.lock.tryLock()) { try { if (from.getBalance() < amount) throw new InsufficientFundsException(); from.debit(amount); to.credit(amount); return true; } finally { to.lock.unlock(); } } } finally { from.lock.unlock(); } } if (System.nanoTime() > stopTime) return false; Thread.sleep(100); } } 六、性能优化建议 减少锁的粒度:尽量缩小同步代码块的范围 读写分离:读多写少时使用读写锁 避免锁的嵌套:减少死锁风险 考虑无锁编程:使用Atomic类等无锁数据结构 合理使用线程池:避免频繁创建销毁线程 通过深入理解线程生命周期和同步锁机制,开发者可以构建出高效、安全的并发Java应用程序。在实际开发中,应根据具体场景选择合适的同步策略,并始终注意线程安全和性能之间的平衡。
29 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传