深入理解线程通信(上)

简介: 开发中不免会遇到需要所有子线程执行完毕通知主线程处理某些逻辑的场景。或者是线程 A 在执行到某个条件通知线程 B 执行某个操作。

前言


开发中不免会遇到需要所有子线程执行完毕通知主线程处理某些逻辑的场景。


或者是线程 A 在执行到某个条件通知线程 B 执行某个操作。


可以通过以下几种方式实现:


等待通知机制


等待通知模式是 Java 中比较经典的线程通信方式。


两个线程通过对同一对象调用等待 wait() 和通知 notify() 方法来进行通讯。


如两个线程交替打印奇偶数:


public class TwoThreadWaitNotify {
    private int start = 1;
    private boolean flag = false;
    public static void main(String[] args) {
        TwoThreadWaitNotify twoThread = new TwoThreadWaitNotify();
        Thread t1 = new Thread(new OuNum(twoThread));
        t1.setName("A");
        Thread t2 = new Thread(new JiNum(twoThread));
        t2.setName("B");
        t1.start();
        t2.start();
    }
    /**
     * 偶数线程
     */
    public static class OuNum implements Runnable {
        private TwoThreadWaitNotify number;
        public OuNum(TwoThreadWaitNotify number) {
            this.number = number;
        }
        @Override
        public void run() {
            while (number.start <= 100) {
                synchronized (TwoThreadWaitNotify.class) {
                    System.out.println("偶数线程抢到锁了");
                    if (number.flag) {
                        System.out.println(Thread.currentThread().getName() + "+-+偶数" + number.start);
                        number.start++;
                        number.flag = false;
                        TwoThreadWaitNotify.class.notify();
                    }else {
                        try {
                            TwoThreadWaitNotify.class.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    /**
     * 奇数线程
     */
    public static class JiNum implements Runnable {
        private TwoThreadWaitNotify number;
        public JiNum(TwoThreadWaitNotify number) {
            this.number = number;
        }
        @Override
        public void run() {
            while (number.start <= 100) {
                synchronized (TwoThreadWaitNotify.class) {
                    System.out.println("奇数线程抢到锁了");
                    if (!number.flag) {
                        System.out.println(Thread.currentThread().getName() + "+-+奇数" + number.start);
                        number.start++;
                        number.flag = true;
                        TwoThreadWaitNotify.class.notify();
                    }else {
                        try {
                            TwoThreadWaitNotify.class.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}


输出结果:


t2+-+奇数93
t1+-+偶数94
t2+-+奇数95
t1+-+偶数96
t2+-+奇数97
t1+-+偶数98
t2+-+奇数99
t1+-+偶数100


这里的线程 A 和线程 B 都对同一个对象 TwoThreadWaitNotify.class 获取锁,A 线程调用了同步对象的 wait() 方法释放了锁并进入 WAITING 状态。


B 线程调用了 notify() 方法,这样 A 线程收到通知之后就可以从 wait() 方法中返回。

这里利用了 TwoThreadWaitNotify.class 对象完成了通信。


有一些需要注意:


  • wait() 、nofify() 、nofityAll() 调用的前提都是获得了对象的锁(也可称为对象监视器)。


  • 调用 wait() 方法后线程会释放锁,进入 WAITING 状态,该线程也会被移动到等待队列中。


  • 调用 notify() 方法会将等待队列中的线程移动到同步队列中,线程状态也会更新为 BLOCKED


  • 从 wait() 方法返回的前提是调用 notify() 方法的线程释放锁,wait() 方法的线程获得锁。


等待通知有着一个经典范式:


线程 A 作为消费者:


  1. 获取对象的锁。


  1. 进入 while(判断条件),并调用 wait() 方法。


  1. 当条件满足跳出循环执行具体处理逻辑。


线程 B 作为生产者:


  1. 获取对象锁。


  1. 更改与线程 A 共用的判断条件。


  1. 调用 notify() 方法。


伪代码如下:


//Thread A
synchronized(Object){
    while(条件){
        Object.wait();
    }
    //do something
}
//Thread B
synchronized(Object){
    条件=false;//改变条件
    Object.notify();
}


相关文章
|
3月前
|
Java
实现Java多线程中的线程间通信
实现Java多线程中的线程间通信
|
4月前
|
Java 程序员
从菜鸟到大神:JAVA多线程通信的wait()、notify()、notifyAll()之旅
【6月更文挑战第21天】Java多线程核心在于wait(), notify(), notifyAll(),它们用于线程间通信与同步,确保数据一致性。wait()让线程释放锁并等待,notify()唤醒一个等待线程,notifyAll()唤醒所有线程。这些方法在解决生产者-消费者问题等场景中扮演关键角色,是程序员从新手到专家进阶的必经之路。通过学习和实践,每个程序员都能在多线程编程的挑战中成长。
44 6
|
4月前
|
Java
Java Socket编程与多线程:提升客户端-服务器通信的并发性能
【6月更文挑战第21天】Java网络编程中,Socket结合多线程提升并发性能,服务器对每个客户端连接启动新线程处理,如示例所示,实现每个客户端的独立操作。多线程利用多核处理器能力,避免串行等待,提升响应速度。防止死锁需减少共享资源,统一锁定顺序,使用超时和重试策略。使用synchronized、ReentrantLock等维持数据一致性。多线程带来性能提升的同时,也伴随复杂性和挑战。
81 0
|
4月前
|
安全 Java
JAVA多线程通信新解:wait()、notify()、notifyAll()的实用技巧
【6月更文挑战第20天】Java多线程中,`wait()`, `notify()`和`notifyAll()`用于线程通信。在生产者-消费者模型示例中,它们确保线程同步。`synchronized`保证安全,`wait()`在循环内防止虚假唤醒,`notifyAll()`避免唤醒单一线程问题。关键技巧包括:循环内调用`wait()`,优先使用`notifyAll()`以保证可靠性,以及确保线程安全和正确处理`InterruptedException`。
41 0
|
2月前
|
存储 安全 Java
【多线程面试题 七】、 说一说Java多线程之间的通信方式
Java多线程之间的通信方式主要有:使用Object类的wait()、notify()、notifyAll()方法进行线程间协调;使用Lock接口的Condition的await()、signal()、signalAll()方法实现更灵活的线程间协作;以及使用BlockingQueue作为线程安全的队列来实现生产者和消费者模型的线程通信。
|
4月前
|
Java 开发者
线程通信的方法和实现技巧详解
线程通信的方法和实现技巧详解
|
3月前
|
Java
实现Java多线程中的线程间通信
实现Java多线程中的线程间通信
|
3月前
|
消息中间件 安全 Java
Java中的线程间通信详解
Java中的线程间通信详解
|
3月前
|
消息中间件 Python
线程通信
【7月更文挑战第1天】
28 2
|
3月前
|
Java
线程间通信的几种方法
线程间通信的几种方法