Java LockSupport案例

wen java案例 1

本文目录导读:

Java LockSupport案例

  1. 基础案例:线程的挂起与恢复
  2. 等待超时机制
  3. 生产者-消费者模式实现
  4. 可中断的等待(响应中断)
  5. 银行账户转账安全示例(实际应用场景)
  6. 高级案例:实现一个简单的AQS(AbstractQueuedSynchronizer)
  7. 注意事项与最佳实践
  8. 关键知识点总结

我将为你提供几个Java LockSupport 的实用案例,从基础到高级,帮助你理解线程阻塞与唤醒机制。

基础案例:线程的挂起与恢复

import java.util.concurrent.locks.LockSupport;
public class BasicLockSupportDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + " 开始执行");
            // 阻塞当前线程,直到被唤醒
            LockSupport.park();
            System.out.println(Thread.currentThread().getName() + " 被唤醒,继续执行");
        }, "Worker-Thread");
        thread.start();
        Thread.sleep(2000); // 主线程休眠2秒
        System.out.println("主线程准备唤醒工作线程");
        // 唤醒指定线程
        LockSupport.unpark(thread);
    }
}

等待超时机制

import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.TimeUnit;
public class TimeoutLockSupportDemo {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("开始等待数据...");
            // 最多等待5秒
            LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
            System.out.println("等待结束,继续执行");
        });
        thread.start();
        // 主线程不主动唤醒,让工作线程超时自动继续
        System.out.println("主线程不唤醒,让工作线程5秒后自动继续");
    }
}

生产者-消费者模式实现

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.LockSupport;
public class ProducerConsumerWithLockSupport {
    private static final Queue<Integer> QUEUE = new LinkedList<>();
    private static final int MAX_SIZE = 5;
    public static void main(String[] args) throws InterruptedException {
        Thread consumerThread = new Thread(new Consumer(), "消费者");
        Thread producerThread = new Thread(new Producer(), "生产者");
        // 先启动消费者,确保它在等待中
        consumerThread.start();
        Thread.sleep(100);
        producerThread.start();
    }
    static class Producer implements Runnable {
        @Override
        public void run() {
            int count = 0;
            while (count < 10) {
                synchronized (QUEUE) {
                    if (QUEUE.size() < MAX_SIZE) {
                        QUEUE.add(count);
                        System.out.println("生产: " + count + ", 队列大小: " + QUEUE.size());
                        count++;
                        // 唤醒消费者
                        LockSupport.unpark(getConsumerThread());
                    }
                }
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    static class Consumer implements Runnable {
        @Override
        public void run() {
            while (true) {
                synchronized (QUEUE) {
                    if (QUEUE.isEmpty()) {
                        System.out.println("队列为空,消费者等待...");
                        LockSupport.park();  // 阻塞消费者
                        System.out.println("消费者被唤醒");
                    } else {
                        Integer item = QUEUE.poll();
                        System.out.println("消费: " + item + ", 队列大小: " + QUEUE.size());
                        if (item != null && item == 9) {
                            break;  // 消费完成
                        }
                    }
                }
            }
        }
    }
    private static Thread getConsumerThread() {
        // 这里简化处理,实际需要记录消费者线程引用
        return Thread.currentThread();
    }
}

可中断的等待(响应中断)

import java.util.concurrent.locks.LockSupport;
public class InterruptibleParkDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            System.out.println("线程开始执行");
            // 检查中断状态
            Thread.currentThread().interrupt();
            // 如果线程被中断,park会立即返回
            LockSupport.park();
            if (Thread.currentThread().isInterrupted()) {
                System.out.println("线程被中断,park立即返回");
                // 清除中断标志
                Thread.interrupted();
            }
            System.out.println("继续执行");
        });
        thread.start();
        thread.join();
        System.out.println("主线程结束");
    }
}

银行账户转账安全示例(实际应用场景)

import java.util.concurrent.locks.LockSupport;
public class BankTransferDemo {
    static class BankAccount {
        private String accountNo;
        private double balance;
        private Thread waitingThread;  // 等待中的线程
        public BankAccount(String accountNo, double balance) {
            this.accountNo = accountNo;
            this.balance = balance;
        }
        public synchronized void transfer(BankAccount to, double amount) {
            System.out.println(Thread.currentThread().getName() + 
                " 尝试从 " + accountNo + " 转账 " + amount + " 到 " + to.accountNo);
            if (balance < amount) {
                System.out.println("余额不足,等待资金到账...");
                // 保存当前线程,以便唤醒
                this.waitingThread = Thread.currentThread();
                // 释放锁并阻塞
                LockSupport.park();
                // 唤醒后重新检查
                if (balance < amount) {
                    System.out.println("唤醒后仍余额不足,再次等待");
                    LockSupport.park();
                }
            }
            this.balance -= amount;
            to.balance += amount;
            System.out.println("转账完成,当前余额: " + balance);
            // 唤醒等待的线程
            if (to.waitingThread != null) {
                LockSupport.unpark(to.waitingThread);
            }
        }
        public void deposit(double amount) {
            this.balance += amount;
            System.out.println("存款后余额: " + balance);
            // 存款后唤醒等待的线程
            if (waitingThread != null) {
                LockSupport.unpark(waitingThread);
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        BankAccount accountA = new BankAccount("A", 100);
        BankAccount accountB = new BankAccount("B", 500);
        // 线程1:从A转账500到B(余额不足)
        Thread t1 = new Thread(() -> {
            accountA.transfer(accountB, 500);
        }, "转账线程-1");
        // 线程2:向A存款600
        Thread t2 = new Thread(() -> {
            try {
                Thread.sleep(2000);  // 延迟存款
                accountA.deposit(600);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "存款线程-2");
        t1.start();
        Thread.sleep(100);
        t2.start();
        t1.join();
        t2.join();
    }
}

高级案例:实现一个简单的AQS(AbstractQueuedSynchronizer)

import java.util.concurrent.locks.LockSupport;
public class SimpleAQS {
    private volatile int state = 0;  // 0:未锁定,1:已锁定
    private Thread owner;  // 当前持有锁的线程
    private Thread head;   // 等待队列头
    private Thread tail;   // 等待队列尾
    private ConcurrentLinkedQueue<Thread> waitQueue = new ConcurrentLinkedQueue<>();
    public void lock() {
        // 尝试获取锁
        if (compareAndSetState(0, 1)) {
            owner = Thread.currentThread();
            return;
        }
        // 获取失败,加入等待队列
        waitQueue.add(Thread.currentThread());
        // 自旋等待
        while (true) {
            if (compareAndSetState(0, 1)) {
                owner = Thread.currentThread();
                waitQueue.remove(Thread.currentThread());
                return;
            }
            // 挂起当前线程
            LockSupport.park();
        }
    }
    public void unlock() {
        if (owner != Thread.currentThread()) {
            throw new IllegalMonitorStateException();
        }
        // 释放锁
        state = 0;
        owner = null;
        // 唤醒下一个等待线程
        Thread nextThread = waitQueue.poll();
        if (nextThread != null) {
            LockSupport.unpark(nextThread);
        }
    }
    private boolean compareAndSetState(int expect, int update) {
        // 这里简化处理,实际应该用AtomicInteger的CAS
        if (state == expect) {
            state = update;
            return true;
        }
        return false;
    }
}
// 测试类
class LockSupportAQSExample {
    public static void main(String[] args) throws InterruptedException {
        SimpleAQS lock = new SimpleAQS();
        Runnable task = () -> {
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + " 获得锁");
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + " 释放锁");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        };
        // 创建多个线程竞争锁
        for (int i = 0; i < 3; i++) {
            new Thread(task, "线程-" + i).start();
        }
        Thread.sleep(5000);
    }
}

注意事项与最佳实践

import java.util.concurrent.locks.LockSupport;
public class LockSupportBestPractices {
    public static void main(String[] args) throws InterruptedException {
        // 1. park和unpark不需要按照特定顺序
        demonstrateOrderIndependence();
        // 2. 可以提前unpark
        demonstrateEarlyUnpark();
        // 3. 中断不会影响unpark
        demonstrateInterruptBehavior();
    }
    private static void demonstrateOrderIndependence() throws InterruptedException {
        System.out.println("=== 演示1:unpark可以先于park执行 ===");
        Thread t1 = new Thread(() -> {
            Thread.currentThread().interrupt();
            LockSupport.park();
            System.out.println("即使先interrupt,也能唤醒");
        });
        t1.start();
        t1.join();
    }
    private static void demonstrateEarlyUnpark() {
        System.out.println("=== 演示2:提前unpark ===");
        Thread t2 = new Thread(() -> {
            // park会立即返回,因为已经有许可
            LockSupport.park();
            System.out.println("线程2立即执行");
        });
        LockSupport.unpark(t2);  // 提前给许可
        t2.start();
    }
    private static void demonstrateInterruptBehavior() throws InterruptedException {
        System.out.println("=== 演示3:中断行为 ===");
        Thread t3 = new Thread(() -> {
            Thread.currentThread().interrupt();  // 设置中断标志
            LockSupport.park();  // 会立即返回
            System.out.println("线程3响应中断");
        });
        t3.start();
        t3.join();
    }
}

关键知识点总结

方法 功能 特点
park() 阻塞当前线程 不可超时
parkNanos(nanos) 带超时的阻塞 自动唤醒
unpark(thread) 唤醒指定线程 可提前给许可
parkUntil(deadline) 指定时间点唤醒 绝对时间

注意事项:

  1. LockSupport是基于许可(permit)机制的,unpark会发送许可
  2. 与Object的wait/notify不同,LockSupport不需要synchronized
  3. 每个线程最多只有一个许可
  4. 不会抛出InterruptedException,但会响应中断标志
  5. 比wait/notify更灵活,可以精确唤醒指定线程

这些案例覆盖了LockSupport的主要使用场景,从基础到实际应用,在实际项目中,它是构建高级并发工具的基础。

抱歉,评论功能暂时关闭!