跳转到内容

Java线程通信

来自代码酷

Java线程通信[编辑 | 编辑源代码]

Java线程通信是多线程编程中的核心概念,指多个线程之间通过共享内存或消息传递机制协调工作。合理使用线程通信可以避免竞态条件、死锁等问题,并提高程序的并发效率。

概述[编辑 | 编辑源代码]

在Java中,线程通信主要通过以下方式实现:

  • 共享对象:通过对象的成员变量或静态变量共享数据
  • wait/notify机制:使用Object类的wait(), notify(), notifyAll()方法
  • 并发工具类:如BlockingQueue、CountDownLatch等

线程通信需要解决两个关键问题: 1. 线程如何安全地共享信息 2. 如何确保线程在正确的时间执行

基本通信机制[编辑 | 编辑源代码]

wait/notify机制[编辑 | 编辑源代码]

这是Java内建的线程通信方式,所有对象都拥有这些方法(因为定义在Object类中)。

public class WaitNotifyExample {
    private static final Object lock = new Object();
    private static boolean condition = false;

    public static void main(String[] args) {
        Thread waitingThread = new Thread(() -> {
            synchronized (lock) {
                while (!condition) {
                    try {
                        System.out.println("等待线程进入等待状态");
                        lock.wait();  // 释放锁并等待
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
                System.out.println("等待线程被唤醒并继续执行");
            }
        });

        Thread notifyingThread = new Thread(() -> {
            synchronized (lock) {
                try {
                    Thread.sleep(2000);  // 模拟工作
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                condition = true;
                lock.notify();  // 唤醒等待的线程
                System.out.println("通知线程发送了通知");
            }
        });

        waitingThread.start();
        notifyingThread.start();
    }
}

输出示例:

等待线程进入等待状态
(2秒后)
通知线程发送了通知
等待线程被唤醒并继续执行

使用BlockingQueue[编辑 | 编辑源代码]

Java并发包提供了线程安全的队列实现:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class BlockingQueueExample {
    public static void main(String[] args) {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);

        // 生产者线程
        new Thread(() -> {
            try {
                String item = "数据-" + System.currentTimeMillis();
                queue.put(item);  // 如果队列满则阻塞
                System.out.println("生产: " + item);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();

        // 消费者线程
        new Thread(() -> {
            try {
                String item = queue.take();  // 如果队列空则阻塞
                System.out.println("消费: " + item);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
    }
}

高级通信模式[编辑 | 编辑源代码]

生产者-消费者模式[编辑 | 编辑源代码]

经典的多线程通信模型,可以使用多种方式实现:

graph LR P[生产者] -->|put| B[缓冲区] B -->|take| C[消费者]

信号量模式[编辑 | 编辑源代码]

使用Semaphore控制资源访问:

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private static final Semaphore semaphore = new Semaphore(1); // 只允许1个线程访问

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + " 获得许可");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    semaphore.release();
                    System.out.println(Thread.currentThread().getName() + " 释放许可");
                }
            }).start();
        }
    }
}

实际应用案例[编辑 | 编辑源代码]

银行转账系统[编辑 | 编辑源代码]

考虑一个银行系统,多个线程同时处理转账请求,需要确保账户余额的正确性:

public class BankTransfer {
    private static class Account {
        private int balance;
        
        public Account(int initialBalance) {
            this.balance = initialBalance;
        }
        
        public synchronized void transfer(Account dest, int amount) {
            if (this.balance >= amount) {
                this.balance -= amount;
                dest.balance += amount;
                System.out.println(Thread.currentThread().getName() + 
                    " 转账成功: " + amount);
            } else {
                System.out.println(Thread.currentThread().getName() + 
                    " 余额不足");
            }
        }
    }

    public static void main(String[] args) {
        Account accountA = new Account(1000);
        Account accountB = new Account(1000);
        
        // 创建多个转账线程
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                for (int j = 0; j < 10; j++) {
                    accountA.transfer(accountB, 50);
                    accountB.transfer(accountA, 30);
                }
            }).start();
        }
    }
}

常见问题与解决方案[编辑 | 编辑源代码]

问题 解决方案
死锁 使用锁顺序、设置超时、避免嵌套锁
活锁 引入随机退避机制
线程饥饿 使用公平锁、合理设置线程优先级

数学基础[编辑 | 编辑源代码]

线程同步问题可以用Petri网建模。对于n个线程访问共享资源的情况,安全条件为:

i=1nxic

其中:

  • xi 是线程i的资源占用数
  • c 是资源总量

最佳实践[编辑 | 编辑源代码]

1. 优先使用高层并发工具(如java.util.concurrent包) 2. 尽量减少同步代码块的范围 3. 避免在同步块中调用外部方法 4. 考虑使用不可变对象 5. 使用线程局部变量(ThreadLocal)避免共享

总结[编辑 | 编辑源代码]

Java线程通信是多线程编程的核心,理解各种通信机制及其适用场景对于编写正确、高效的并发程序至关重要。从基本的wait/notify到高级的并发工具类,Java提供了丰富的线程通信方式。开发者应根据具体需求选择最合适的通信机制,同时注意避免常见的并发问题。