线程间的通信

简介: 线程间的通信
  • 线程间的通讯技术就是通过等待和唤醒机制,来实现多个线程协同操作完成某一项任务,例如经典的生产者和消费者案例。等待唤醒机制其实就是让线程进入等待状态或者让线程从等待状态中唤醒,需要用到两种方法,如下:


  • 等待方法 :


void wait() 让线程进入无限等待。

void wait(long timeout) 让线程进入计时等待

以上两个方法调用会导致当前线程释放掉锁资源。


  • 唤醒方法 :


void notify() 唤醒在此对象监视器(锁对象)上等待的单个线程。

void notifyAll() 唤醒在此对象监视器上等待的所有线程。

以上两个方法调用不会导致当前线程释放掉锁资源


  • 注意


等待和唤醒的方法,都要使用锁对象调用(需要在同步代码块中调用)

等待和唤醒方法应该使用相同的锁对象调用


/*

1 线程进入无限等待

注意:进入无限等待需要使用锁在同步代码中调用wait方法

*/

/*
    1 线程进入无限等待
        注意:进入无限等待需要使用锁在同步代码中调用wait方法
 */
public class Test1 {
    public static void main(String[] args) {
        Object obj = new Object(); // 作为锁对象

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj) {
                    System.out.println("线程开始执行");
                    System.out.println("线程进入无线等待....");
                    try {
                        obj.wait(); // 进入无线等待状态 , 并释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("无线等待被唤醒....");
                }
            }
        }).start();
    }
}

/*

线程进入无限等待后被唤醒

注意:等待和唤醒是两个或多个线程之间实现的。进入无限等待的线程是不会自动唤醒,只能通过其他线程来唤醒。

*/

/*
    线程进入无限等待后被唤醒
    注意:等待和唤醒是两个或多个线程之间实现的。进入无限等待的线程是不会自动唤醒,只能通过其他线程来唤醒。
 */
public class Test2 {
    public static void main(String[] args) {
        Object obj = new Object(); // 作为锁对象

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj) {
                    System.out.println("线程开始执行");
                    System.out.println("线程进入无线等待....");
                    try {
                        obj.wait(); // 进入无线等待状态 , 并释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("无线等待被唤醒....");
                }
            }
        }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (obj) {
                    obj.notify();// 随机唤醒此监视器中等待的线程 , 不会释放锁
                    System.out.println("唤醒后 , 5秒钟后释放锁");
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }// 释放锁
            }
        }).start();
    }
}

/*

3 线程进入计时等待并唤醒

注意:进入计时等待的线程,时间结束前可以被其他线程唤醒。时间结束后会自动唤醒

*/

/*
    3 线程进入计时等待并唤醒
        注意:进入计时等待的线程,时间结束前可以被其他线程唤醒。时间结束后会自动唤醒
 */
public class Test3 {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (Test3.class) {
                    System.out.println("获取到锁 , 开始执行");
                    try {
                        System.out.println("进入计时等待...3秒");
                        Test3.class.wait(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("自动唤醒.");
                }
            }
        }).start();
    }
}

生产者和消费者案例

/*

生产者步骤:

1,判断桌子上是否有汉堡包

如果有就等待,如果没有才生产。

2,把汉堡包放在桌子上。

3,叫醒等待的消费者开吃

*/

import sun.security.krb5.internal.crypto.Des;

/*
    生产者步骤:
        1,判断桌子上是否有汉堡包
            如果有就等待,如果没有才生产。
        2,把汉堡包放在桌子上。
        3,叫醒等待的消费者开吃
 */
public class Cooker implements Runnable {
    @Override
    public void run() {
        while (true) {
            synchronized (Desk.lock) {
                if (Desk.count == 0) {
                    break;
                } else {
                    if (Desk.flag) {
                        // 桌子上有食物
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        // 桌子上没有食物
                        System.out.println("厨师生产了一个汉堡包...");
                        Desk.flag = true;
                        Desk.lock.notify();
                    }
                }
            }
        }
    }
}

/*

消费者步骤:

1,判断桌子上是否有汉堡包。

2,如果没有就等待。

3,如果有就开吃

4,吃完之后,桌子上的汉堡包就没有了

叫醒等待的生产者继续生产

汉堡包的总数量减一

*/

import sun.security.krb5.internal.crypto.Des;

/*
    消费者步骤:
        1,判断桌子上是否有汉堡包。
        2,如果没有就等待。
        3,如果有就开吃
        4,吃完之后,桌子上的汉堡包就没有了
            叫醒等待的生产者继续生产
            汉堡包的总数量减一
 */
public class Foodie implements Runnable {
    @Override
    public void run() {
        while (true) {
            synchronized (Desk.lock) {
                if (Desk.count == 0) {
                    break;
                } else {
                    if (Desk.flag) {
                        // 桌子上有食物
                        System.out.println("吃货吃了一个汉堡包...");
                        Desk.count--; // 汉堡包的数量减少一个
                        Desk.flag = false;// 桌子上的食物被吃掉 , 值为false
                        Desk.lock.notify();
                    } else {
                        // 桌子上没有食物
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}
public class Test {
    public static void main(String[] args) {
        new Thread(new Foodie()).start();
        new Thread(new Cooker()).start();
    }
}
相关文章
|
5天前
|
Java 调度
[Java]线程生命周期与线程通信
本文详细探讨了线程生命周期与线程通信。文章首先分析了线程的五个基本状态及其转换过程,结合JDK1.8版本的特点进行了深入讲解。接着,通过多个实例介绍了线程通信的几种实现方式,包括使用`volatile`关键字、`Object`类的`wait()`和`notify()`方法、`CountDownLatch`、`ReentrantLock`结合`Condition`以及`LockSupport`等工具。全文旨在帮助读者理解线程管理的核心概念和技术细节。
18 1
[Java]线程生命周期与线程通信
|
4月前
|
Java
实现Java多线程中的线程间通信
实现Java多线程中的线程间通信
|
5月前
|
Java 程序员
从菜鸟到大神:JAVA多线程通信的wait()、notify()、notifyAll()之旅
【6月更文挑战第21天】Java多线程核心在于wait(), notify(), notifyAll(),它们用于线程间通信与同步,确保数据一致性。wait()让线程释放锁并等待,notify()唤醒一个等待线程,notifyAll()唤醒所有线程。这些方法在解决生产者-消费者问题等场景中扮演关键角色,是程序员从新手到专家进阶的必经之路。通过学习和实践,每个程序员都能在多线程编程的挑战中成长。
53 6
|
6天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
8 1
|
6天前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
16 1
|
6天前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
13 1
|
16天前
|
Java
|
5月前
|
Java
Java Socket编程与多线程:提升客户端-服务器通信的并发性能
【6月更文挑战第21天】Java网络编程中,Socket结合多线程提升并发性能,服务器对每个客户端连接启动新线程处理,如示例所示,实现每个客户端的独立操作。多线程利用多核处理器能力,避免串行等待,提升响应速度。防止死锁需减少共享资源,统一锁定顺序,使用超时和重试策略。使用synchronized、ReentrantLock等维持数据一致性。多线程带来性能提升的同时,也伴随复杂性和挑战。
95 0
|
5月前
|
安全 Java
JAVA多线程通信新解:wait()、notify()、notifyAll()的实用技巧
【6月更文挑战第20天】Java多线程中,`wait()`, `notify()`和`notifyAll()`用于线程通信。在生产者-消费者模型示例中,它们确保线程同步。`synchronized`保证安全,`wait()`在循环内防止虚假唤醒,`notifyAll()`避免唤醒单一线程问题。关键技巧包括:循环内调用`wait()`,优先使用`notifyAll()`以保证可靠性,以及确保线程安全和正确处理`InterruptedException`。
49 0
|
16天前
多线程通信和同步的方式有哪些?
【10月更文挑战第6天】
76 0