线程间的通信

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


  • 等待方法 :


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();
    }
}
相关文章
|
1月前
|
存储 Java 数据库连接
java多线程之线程通信
java多线程之线程通信
|
1月前
|
Python
如何在Python中实现线程之间的同步和通信?
【2月更文挑战第17天】【2月更文挑战第51篇】如何在Python中实现线程之间的同步和通信?
|
1月前
|
Java
线程间通信之Object.wait/notify实现
线程间通信之Object.wait/notify实现
41 0
|
1月前
|
消息中间件 存储 Unix
进程间通信和线程间通信总结
写在前面 面试的时候一定不要疲劳战,比如上午面了一个,然后中午不休息直接赶到另外一个相距比较远的公司,影响状态。 面试的时候一定不要紧张,不管对方有几个人,总之面试的时候做好充分准备,休息好,放松心态。 好了,言归正传,开始总结。
46 0
|
6天前
|
存储 安全 Java
Java并发基础-线程间通信
Java并发基础-线程间通信
6 0
|
18天前
|
安全 Java
Java的线程同步与通信:深入理解wait、notify和synchronized
Java的线程同步与通信:深入理解wait、notify和synchronized
14 0
|
19天前
|
Java 程序员
线程会很感谢你的,给它一个可以通信的传话筒
每个Java线程开始运行,按照你写的逻辑一步步的执行着,就像一个可怜的脚本,孤独地活着!只有它们内部的栈空间、程序计数器在陪伴着它们。 大家给可怜的单线程多加几个玩伴吗?创建一个多线程环境,给它们一个传话筒,让它们可以互相通信、互相问好、嬉皮打闹,看来单线程会很感谢你的。
35 0
线程会很感谢你的,给它一个可以通信的传话筒
|
26天前
|
Java 调度
【JAVA学习之路 | 提高篇】线程的通信
【JAVA学习之路 | 提高篇】线程的通信
|
30天前
|
Java
Java一分钟之-并发编程:线程间通信(Phaser, CyclicBarrier, Semaphore)
【5月更文挑战第19天】Java并发编程中,Phaser、CyclicBarrier和Semaphore是三种强大的同步工具。Phaser用于阶段性任务协调,支持动态注册;CyclicBarrier允许线程同步执行,适合循环任务;Semaphore控制资源访问线程数,常用于限流和资源池管理。了解其使用场景、常见问题及避免策略,结合代码示例,能有效提升并发程序效率。注意异常处理和资源管理,以防止并发问题。
41 2
|
1月前
|
存储 NoSQL Redis
深入浅出Redis(二):Redis单线程模型与通信流程
深入浅出Redis(二):Redis单线程模型与通信流程

热门文章

最新文章