【Java】多线程(四)多线程通讯

本文详细介绍了Java多线程中的线程通讯机制,包括wait/notify和join方法的使用。通过实例展示了如何利用wait/notify实现生产者消费者模型,解释了wait、notify和notifyAll在同步块中的作用。此外,还探讨了join方法的使用,以及它与wait和sleep的区别,并分析了join方法的底层工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

4. 多线程线程之间的通讯

4.1 wait/notify机制

等待/通知的相关方法是任意Java对象都具备的,因为这些方法被定义在所有对象的超类java.lang.Object上,方法如下:

  • notify() :通知一个在对象上等待的线程,使其从wait()方法返回,而返回的前提是该线程获取到了对象的锁

  • notifyAll():通知所有等待在该对象的线程

  • wait():调用该方法的线程进入WAITING状态,只有等待其他线程的通知或者被中断,才会返回。需要注意调用wait()方法后,会释放对象的锁

注意: wait,notify和notifyAll要与synchronized一起使用 否则将会报错

synchronized作用的对象可以是任意一个, 因此wait/notify/notifyAll都是Object的方法

4.1.1 wait/notify/notifyall基本使用
public class MyThread extends Thread {

    @Override
    public void run() {
        //上锁对象为myThread
        synchronized (this){
            try {
                System.out.println("myThread对象调用wait方法,myThread线程进入WAITING状态,并释放myThread对象锁");
                this.wait();
                System.out.println("wait()已返回");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (myThread){
            System.out.println("3秒后唤醒在myThread对象上等待的myThread线程");
            myThread.notify();
        }
    }
}
4.1.2 多线程通讯实现生产者消费者模型
public class MyModelTest {

    class MyResource {
        public String name;
        public int age;
        //是否能消费标记
        public boolean flag = false;
    }

    //消费者线程类
    class ConsumerThread extends Thread{
        private MyResource myResource;
        ConsumerThread(MyResource myResource){
            this.myResource = myResource;
        }
        @Override
        public void run() {
            while (true){
                synchronized (myResource){
                    //不能消费则等待
                    if (!myResource.flag){
                        try {
                            myResource.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //进行消费
                    System.out.println("消费资源: name="+ myResource.name + " age="+myResource.age);
                    //完成消费
                    myResource.flag = false;
                    myResource.notify();
                }
            }
        }
    }

    //生产者线程类
    class ProviderThread extends Thread{
        private MyResource myResource;
        ProviderThread (MyResource myResource){
            this.myResource = myResource;
        }
        @Override
        public void run() {
            int count = 0;
            while (true) {
                synchronized (myResource) {
                    //不能生产则等待
                    if (myResource.flag){
                        try {
                            myResource.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //进行生产
                    if (count % 2 == 0){
                        myResource.name = "张三";
                        myResource.age = 15;
                    }else {
                        myResource.name = "李四";
                        myResource.age = 28;
                    }
                    //完成生产
                    myResource.flag = true;
                    myResource.notify();
                }
                count = (count + 1) % 2;
            }

        }
    }

    public static void main(String[] args) {
        new MyModelTest().start();
    }

    public void start(){
        MyResource myResource = new MyResource();
        ProviderThread providerThread = new ProviderThread(myResource);
        ConsumerThread consumerThread = new ConsumerThread(myResource);
        providerThread.start();
        consumerThread.start();
    }
}

4.2 join机制

现有两个线程A、B,在线程A中调用 B.join() 使得线程A在等待线程B执行完以后再执行

4.2.1 join/Wait/sleep之间的区别

join(long)方法先执行另外的一个线程,在等待的过程中释放对象锁 底层是基于wait封装的

sleep(long)方法在睡眠时不释放对象锁

Wait(long)方法在等待的过程中释放对象锁

4.2.2 join基本使用
public class JoinThread {


    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                Thread.sleep(3000);
            } catch (Exception e) {

            }
            System.out.println(Thread.currentThread().getName() + ",线程执行");
        }, "t1");
        Thread t2 = new Thread(() -> {
            try {
                t1.join();
            } catch (InterruptedException e) {

            }
            System.out.println(Thread.currentThread().getName() + ",线程执行");
        }, "t2");
        Thread t3 = new Thread(() -> {
            try {
                t2.join();
            } catch (InterruptedException e) {

            }
            System.out.println(Thread.currentThread().getName() + ",线程执行");
        }, "t3");
        t1.start();
        t2.start();
        t3.start();
    }
}


4.2.3 join的底层原理

Join底层原理是基于wait封装的,其方法上标有synchronized锁,也就是说调用t1线程join方法的t2线程会在t1线程对象上进行等待,但唤醒的代码在jvm Hotspot 源码中

当jvm在关闭线程之前会检测线阻塞在t1线程对象上的线程,然后执行notfyAll(),这样t2就被唤醒了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值