首页 > Java > java教程 > 正文

java如何实现多线程的同步与通信 java多线程同步通信的详细教程​

雪夜
发布: 2025-08-01 16:09:01
原创
131人浏览过

wait()/notify()是java内置的线程通信机制,必须在synchronized中使用,操作对象监视器,且一个锁只能对应一个等待队列;2. condition是lock接口的配套工具,一个lock可创建多个condition,实现多个等待队列,支持更精确的线程唤醒控制;3. blockingqueue是基于阻塞的线程安全队列,内部封装了生产者-消费者模式的同步与通信逻辑,适合简化此类场景的开发,无需手动处理wait/notify或condition的复杂逻辑,当需要高效实现生产者-消费者协作时应优先使用blockingqueue。

java如何实现多线程的同步与通信 java多线程同步通信的详细教程​

Java中实现多线程的同步与通信,核心在于确保共享数据的安全访问和线程间的有效协作。这主要通过锁机制(如

synchronized
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
关键字、
ReentrantLock
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
)、等待/通知机制(
wait()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
/
notify()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
/
notifyAll()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
Condition
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
)、以及一系列高级并发工具类(如
CountDownLatch
登录后复制
登录后复制
CyclicBarrier
登录后复制
登录后复制
Semaphore
登录后复制
登录后复制
BlockingQueue
登录后复制
登录后复制
登录后复制
登录后复制
)来达成。理解并恰当运用这些工具,是编写健壮、高效并发程序的关键。

java如何实现多线程的同步与通信 java多线程同步通信的详细教程​

Java多线程同步通信的详细教程

在Java多线程编程里,同步与通信是绕不开的话题。我个人觉得,这就像是给一群独立的舞者编排一场群舞,如果没有统一的节拍和彼此间的信号,那最终呈现的肯定是一团乱麻。

立即学习Java免费学习笔记(深入)”;

java如何实现多线程的同步与通信 java多线程同步通信的详细教程​

同步(Synchronization) 同步的目的是为了控制多个线程对共享资源的访问,防止数据不一致或竞态条件(Race Condition)的发生。

  1. synchronized
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    关键字: 这是Java语言层面提供的最基本的同步机制。它可以修饰方法或代码块。当修饰方法时,它锁定的是当前实例对象(非静态方法)或类的Class对象(静态方法);当修饰代码块时,它锁定的是括号内指定的对象。 我刚开始用
    synchronized
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    的时候,觉得它真是简单粗暴又有效。比如,你有一个计数器,多个线程去加,不加
    synchronized
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    肯定会出问题。

    java如何实现多线程的同步与通信 java多线程同步通信的详细教程​
    // 示例:synchronized方法
    public synchronized void increment() {
        count++;
    }
    
    // 示例:synchronized代码块
    public void updateList(List<String> sharedList, String item) {
        synchronized (sharedList) { // 锁定共享列表对象
            sharedList.add(item);
        }
    }
    登录后复制

    synchronized
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    的优点在于它由JVM自动管理锁的获取和释放,即使发生异常也能保证锁被释放,避免死锁。但缺点也很明显,它不够灵活,比如无法尝试获取锁,也无法中断一个正在等待锁的线程。

  2. java.util.concurrent.locks.Lock
    登录后复制
    接口(如
    ReentrantLock
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    ):
    这是J.U.C(
    java.util.concurrent
    登录后复制
    登录后复制
    )包提供的一种更灵活、功能更强大的锁机制。
    ReentrantLock
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    Lock
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    接口最常用的实现类,它提供了与
    synchronized
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    相同的基础互斥功能,并且是可重入的。 用
    ReentrantLock
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    ,我感觉就像从一个自动挡的车换到了手动挡,虽然需要自己踩离合、换挡,但你能更好地控制车的性能和行为。它提供了
    lock()
    登录后复制
    unlock()
    登录后复制
    登录后复制
    方法来手动加锁和解锁,这给了开发者更大的控制权。

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    class Counter {
        private int count = 0;
        private final Lock lock = new ReentrantLock();
    
        public void increment() {
            lock.lock(); // 手动加锁
            try {
                count++;
            } finally {
                lock.unlock(); // 确保锁被释放
            }
        }
    }
    登录后复制

    ReentrantLock
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    的优势在于:

    • 可尝试加锁(
      tryLock()
      登录后复制
      登录后复制
      ):
      尝试获取锁,如果获取不到立即返回,不会一直等待。
    • 可中断加锁(
      lockInterruptibly()
      登录后复制
      登录后复制
      ):
      在等待锁的过程中,线程可以被中断。
    • 公平性(Fairness): 可以选择公平锁或非公平锁(默认非公平)。公平锁会按照请求的顺序获取锁,但性能通常会差一些。
    • 配合
      Condition
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      实现更细粒度的通信。

通信(Communication) 通信的目的是让线程之间能够互相发送信号,协作完成任务。

  1. Object
    登录后复制
    类的
    wait()
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    /
    notify()
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    /
    notifyAll()
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    这组方法是Java中最基础的线程间通信机制,它们都必须在
    synchronized
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    代码块或方法中使用,因为它们操作的是对象的监视器锁(monitor lock)。
    wait()
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    方法会使当前线程释放它所持有的锁,并进入等待状态,直到被
    notify()
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    notifyAll()
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    唤醒。
    notify()
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    随机唤醒一个等待在当前对象监视器上的线程。
    notifyAll()
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    唤醒所有等待在当前对象监视器上的线程。 我刚接触这组方法时,总觉得它们有点“魔法”,但一旦理解了它们和锁的绑定关系,就觉得它们真是线程协作的核心。

    class MessageQueue {
        private String message;
        private boolean hasMessage = false;
    
        public synchronized void put(String msg) {
            while (hasMessage) { // 避免虚假唤醒
                try {
                    wait(); // 等待消费者取走消息
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            this.message = msg;
            this.hasMessage = true;
            notifyAll(); // 通知消费者有新消息了
        }
    
        public synchronized String take() {
            while (!hasMessage) { // 避免虚假唤醒
                try {
                    wait(); // 等待生产者放入消息
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            String msg = this.message;
            this.hasMessage = false;
            notifyAll(); // 通知生产者可以放新消息了
            return msg;
        }
    }
    登录后复制
  2. java.util.concurrent.locks.Condition
    登录后复制
    接口:
    Condition
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    是与
    Lock
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    接口配合使用的,它提供了比
    wait()
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    /
    notify()
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    更强大的线程间协作能力。一个
    Lock
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    对象可以创建多个
    Condition
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    实例,每个
    Condition
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    实例都对应一个独立的等待队列。 这就像是给不同类型的等待者划分了不同的等候室,只唤醒特定等候室里的线程,避免了
    notifyAll()
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    可能带来的效率问题。

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    class BoundedBuffer {
        final Lock lock = new ReentrantLock();
        final Condition notFull = lock.newCondition(); // 缓冲区不满的条件
        final Condition notEmpty = lock.newCondition(); // 缓冲区不空的条件
        final Object[] items = new Object[100];
        int putptr, takeptr, count;
    
        public void put(Object x) throws InterruptedException {
            lock.lock();
            try {
                while (count == items.length) {
                    notFull.await(); // 缓冲区满,等待notFull条件
                }
                items[putptr] = x;
                if (++putptr == items.length) putptr = 0;
                ++count;
                notEmpty.signal(); // 通知notEmpty条件等待的线程(有新元素了)
            } finally {
                lock.unlock();
            }
        }
    
        public Object take() throws InterruptedException {
            lock.lock();
            try {
                while (count == 0) {
                    notEmpty.await(); // 缓冲区空,等待notEmpty条件
                }
                Object x = items[takeptr];
                if (++takeptr == items.length) takeptr = 0;
                --count;
                notFull.signal(); // 通知notFull条件等待的线程(有空位了)
                return x;
            } finally {
                lock.unlock();
            }
        }
    }
    登录后复制
  3. java.util.concurrent
    登录后复制
    登录后复制
    包中的高级工具类: J.U.C包提供了许多开箱即用的高级并发工具,它们内部已经处理好了复杂的同步和通信逻辑,极大简化了并发编程。

    • CountDownLatch
      登录后复制
      登录后复制
      一个或多个线程等待其他线程完成一组操作。
    • CyclicBarrier
      登录后复制
      登录后复制
      多个线程相互等待,直到所有线程都到达一个公共屏障点。
    • Semaphore
      登录后复制
      登录后复制
      控制同时访问某个资源的线程数量。
    • BlockingQueue
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      阻塞队列,在队列为空时获取元素的线程会被阻塞,在队列满时添加元素的线程会被阻塞。这是实现生产者-消费者模式的利器。
    • Exchanger
      登录后复制
      用于两个线程之间交换数据。

    这些工具类,简直是并发编程的“瑞士军刀”,很多复杂的同步通信场景,用它们能瞬间变得优雅和高效。比如

    BlockingQueue
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    ,我几乎每次写生产者消费者模式都离不开它,它把所有同步细节都封装好了,我只需要关注业务逻辑。

Java多线程同步为何如此重要?它解决了哪些核心问题?

多线程同步的重要性,在我看来,就像是给高速公路上飞驰的汽车设置交通规则。如果没有这些规则,即使车速再快,也迟早会因为混乱而发生事故。在多线程编程中,这些“事故”通常表现为数据错误或程序崩溃。

它主要解决了以下几个核心问题:

  1. 竞态条件(Race Conditions): 这是最常见的问题。当多个线程同时访问和修改共享数据时,最终结果取决于线程执行的时序,这种不确定性就叫竞态条件。比如,两个线程同时对一个变量执行
    i++
    登录后复制
    登录后复制
    ,最终结果可能不是预期的加2,而是加1。同步机制确保了在特定时间内,只有一个线程能对共享资源进行操作,从而避免了这种不确定性。
  2. 数据不一致性(Data Inconsistency): 由于竞态条件的存在,共享变量在不同线程看来可能处于不同的状态,或者最终状态是错误的。同步机制保证了数据在并发环境下的可见性(Visibility)和原子性(Atomicity),确保所有线程看到的数据都是最新、最准确的。
  3. 原子性(Atomicity)问题: 一些看似简单的操作,比如
    i++
    登录后复制
    登录后复制
    ,实际上包含了读取、修改、写入三个步骤。在多线程环境下,这三个步骤可能被其他线程打断。同步确保了一组操作要么全部完成,要么全部不完成,中间不会被其他线程打断。
  4. 可见性(Visibility)问题: Java内存模型规定,每个线程都有自己的工作内存,线程对共享变量的修改可能不会立即同步到主内存,其他线程也可能看不到最新的值。同步机制(比如
    synchronized
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    登录后复制
    volatile
    登录后复制
    关键字)能强制线程将工作内存中的修改刷新到主内存,并从主内存中读取最新值,从而保证了可见性。
  5. 有序性(Ordering)问题: 编译器和处理器为了优化性能,可能会对指令进行重排序。在单线程环境下这通常不会有问题,但在多线程环境下,重排序可能导致意想不到的错误。同步机制通过内存屏障(Memory Barrier)来限制指令重排序,确保了操作的有序性。

回想起来,我刚开始写多线程代码时,总是被这些“幽灵bug”折磨,数据莫名其妙地错了,后来才意识到,都是同步没做好。所以,同步不仅仅是让程序跑起来,更是让它“跑对”。

在Java中,
synchronized
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
Lock
登录后复制
登录后复制
登录后复制
登录后复制
接口(如
ReentrantLock
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
)各自适用于哪些场景?如何选择?

在Java并发编程中,

synchronized
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
ReentrantLock
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
都是实现线程同步的利器,但它们各有侧重,选择哪一个往往取决于具体的场景需求。我一般会先考虑
synchronized
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
,因为它简单直观,能解决大部分问题。但如果我发现需要更精细的控制,比如想在等待锁的时候能被中断,或者需要尝试获取锁,那肯定就转向
ReentrantLock
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
了。

synchronized
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
的适用场景及特点:

  • 优点:
    • 简洁性: 语法简单,直接在方法或代码块上使用,不需要手动释放锁,JVM会自动处理。
    • 安全性: 即使发生异常,JVM也能确保锁的释放,避免死锁(由于未释放锁导致的)。
    • 内置支持: 是Java语言的关键字,无需引入额外库。
    • JVM优化: 随着Java版本的迭代,
      synchronized
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      在性能上得到了大量优化,如偏向锁、轻量级锁等,在低竞争或无竞争情况下性能非常高。
  • 缺点:
    • 灵活性差: 无法中断一个正在等待锁的线程;无法尝试非阻塞地获取锁;一个
      synchronized
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      块只能关联一个条件变量(通过
      Object.wait()/notify()
      登录后复制
      )。
    • 粒度粗: 只能实现独占式锁,无法实现读写分离锁等更细粒度的控制。
  • 适用场景:
    • 简单同步需求: 当你需要快速、简单地保护一个共享资源时,
      synchronized
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      是首选。
    • 小粒度代码块: 保护的代码逻辑不复杂,执行时间短。
    • 不关心锁的获取方式: 不需要非阻塞、可中断或定时获取锁的场景。
    • 对性能要求不是极致苛刻: 在高并发、高竞争环境下,
      ReentrantLock
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      可能表现更好,但在一般情况下
      synchronized
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      足以胜任。

ReentrantLock
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
的适用场景及特点:

  • 优点:
    • 灵活性高:
      • 可中断:
        lockInterruptibly()
        登录后复制
        登录后复制
        允许在等待锁时响应中断。
      • 可尝试:
        tryLock()
        登录后复制
        登录后复制
        可以尝试获取锁,如果获取不到立即返回,避免无限等待。
      • 公平性: 可以创建公平锁(
        new ReentrantLock(true)
        登录后复制
        ),按请求顺序获取锁,避免饥饿。
      • 多条件变量: 可以配合
        Condition
        登录后复制
        登录后复制
        登录后复制
        登录后复制
        登录后复制
        登录后复制
        登录后复制
        登录后复制
        接口实现多个等待队列,实现更细粒度的线程通信(生产者-消费者模式中非常有用)。
    • 性能: 在高竞争环境下,
      ReentrantLock
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      通常比
      synchronized
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      有更好的性能表现,因为它基于AQS(AbstractQueuedSynchronizer)框架,提供了更高效的队列管理。
  • 缺点:
    • 手动释放锁: 必须手动调用
      unlock()
      登录后复制
      登录后复制
      方法释放锁,通常放在
      finally
      登录后复制
      块中,否则容易造成死锁。
    • 代码更复杂: 相较于
      synchronized
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      ,需要更多的代码来管理锁的生命周期。
  • 适用场景:
    • 复杂同步逻辑: 需要非阻塞地获取锁、可中断地获取锁、或者需要超时获取锁的场景。
    • 细粒度控制: 需要实现读写锁(
      ReentrantReadWriteLock
      登录后复制
      )或者多个条件变量来协调线程的复杂通信。
    • 高并发、高竞争环境: 当性能成为瓶颈时,
      ReentrantLock
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      登录后复制
      可能是更好的选择。
    • 需要公平性: 当业务要求线程按请求顺序获取锁时。

如何选择?

我的经验是,除非有明确的需求(比如需要可中断的锁、非阻塞的锁、或者多个条件变量),否则优先考虑

synchronized
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
。它简单、安全、由JVM优化,能满足大部分并发需求。

只有当

synchronized
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
无法满足特定高级功能,或者通过性能测试发现
synchronized
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
确实是瓶颈时,我才会转向
ReentrantLock
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
。特别是在实现生产者-消费者模式时,
ReentrantLock
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
配合
Condition
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
简直是绝配,比
synchronized
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
+
wait
登录后复制
/
notify
登录后复制
组合用起来要清晰得多,因为它能精确地唤醒等待特定条件的线程。

Java多线程通信中,
wait()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
/
notify()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
Condition
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制
有什么区别?何时使用
BlockingQueue
登录后复制
登录后复制
登录后复制
登录后复制
进行

以上就是java如何实现多线程的同步与通信 java多线程同步通信的详细教程​的详细内容,更多请关注php中文网其它相关文章!

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 //m.sbmmt.com/ All Rights Reserved | php.cn | 湘ICP备2023035733号