【多线程 四】线程间的通信

1、为什么要处理线程间通信 :

当我们需要多个线程共同协作完成一件任务,并且希望他们有规律的执行,那么此时就需要线程之间进行通信。为了能达到此种目的我们需要引入一个机制——等待唤醒机制。

2、 等待唤醒机制

这是多个线程间的一种协作机制。
就是在一个线程进行了规定操作后 ,就进入等待状态 (wait() ), 等待其他线程执行完他们的指定代码过后 再将 其唤醒 (notify() );在有多个线程进行等待时, 如果需要 ,可以使用 notifyAll()来唤醒所有的等待线程。

2.1 wait() 与notify() 和notifyAll()
wait():令当前线程挂起并放弃CPU、同步资源并等待
  • 在当前线程中调用方法: 对象名.wait()
  • 使当前线程进入等待(某对象)状态,直到另一线程对该对象发出notify (或notifyAll) 为止。
  • 调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)
  • 调用此方法后,当前线程将释放对象监控权,然后进入等待
  • 在当前线程被notify后,要重新获得监控权,然后从断点处继续代码的执行。
notify()/notifyAll()
  • 在当前线程中调用方法: 对象名.notify() 或者 对象名.notifyAll()

  • 功能:唤醒等待该对象监控权的一个或者所有线程。

  • 调用方法的必要条件:当前线程必须调用了wait()

2.2 面试题:

编写一个程序,开启三个线程,这三个线程的名字分别为A,B,C 每个线程将自己的名字打印10次,交替打印,如ABCABCABCABCABCABC…

方法1:jdk1.5 前:wait()、notify()
代码:

//两个线程交替执行
public class TestABABAB {
    public static int flag = 1;
    public static void main(String[] args) {
        // 1、线程通信,需要wait notify  但是这两个必须和synchronize共同使用
        Object objA = new Object();
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (objA) {
                    for (int i = 0; i < 10; i++) {
                        while (flag != 1) {
                            try {
                                objA.wait();             
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName());
                        flag = 2;
                        objA.notifyAll();
                    }
                }
            }
        }, "A").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (objA) {
                    for (int i = 0; i < 10; i++) {
                        while (flag != 2) {
                            try {
                                objA.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName());
                        flag = 3;
                        objA.notifyAll();
                    }
                }
            }
        }, "B").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (objA) {
                    for (int i = 0; i < 10; i++) {
                        while (flag != 3) {
                            try {
                                objA.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName());
                        flag = 1;
                        objA.notifyAll();
                    }
                }
            }
        }, "C").start();
    }
}

执行结果:
在这里插入图片描述

jdk1.5后 lock() 和condition
Condition 接口描述了可能会与锁有关联的条件变量。这些变量在用 法上与使Object.wait 访问的隐式监视器类似,但提供了更强大的 功能。需要特别指出的是,单个 Lock 可能与多个 Condition 对象关 联。为了避免兼容性问题,Condition 方法的名称与对应的 Object 版 本中的不同。

在 Condition 对象中,与 wait、notify 和 notifyAll 方法对应的分别是 await、signal 和 signalAll。

Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。

代码:

public class TestABABAB1 {
    public static int flag = 1;

    public static void main(String[] args) {
        // 1、线程通信,需要wait notify  但是这两个必须和synchronize共同使用
        Lock lock = new ReentrantLock();
        Condition conditionA = lock.newCondition();
        Condition conditionB = lock.newCondition();
        Condition conditionC = lock.newCondition();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    lock.lock();
                    try {
                        if (flag != 2) {
                            try {
                                conditionB.await();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName());
                        flag = 3;
                        conditionC.signal();
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }, "B").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    lock.lock();
                    try {
                        if (flag != 3) {
                            try {
                                conditionC.await();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName());
                        flag = 1;
                        conditionA.signal();
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }, "C").start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    lock.lock();
                    try {
                        if (flag != 1) {
                            try {
                                conditionA.await();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName());
                        flag = 2;
                        conditionB.signal();
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }, "A").start();
    }
}

下面给一个链接:https://www.jianshu.com/p/40078ed436b4 下面是这道题目的四种优雅写法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值