欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识

只要 A B C 昆山软件开发 都运行完了

点击: 次  来源:宝鼎软件 时间:2017-10-07

原文出处: wingjay

正常环境下,每个子线程完成各自的任务就可以竣事了。不外有的时候,我们但愿多个线程协同事情来完成某个任务,这时就涉及到了线程间通信了。

本文涉及到的常识点:thread.join(), object.wait(), object.notify(), CountdownLatch, CyclicBarrier, FutureTask, Callable 等。

本文涉及代码:

https://github.com/wingjay/HelloJava/blob/master/multi-thread/src/ForArticle.java

下面我从几个例子作为切入点来讲授下 Java 里有哪些要领来实现线程间通信。

  • 如何让两个线程依次执行?
  • 那如何让 两个线程凭据指定方法有序交错运行呢?
  • 四个线程 A B C D,个中 D 要比及 A B C 全执行完毕后才执行,并且 A B C 是同步运行的
  • 三个运带动各自筹备,比及三小我私家都筹备好后,再一起跑
  • 子线程完成某件任务后,把获得的功效回传给主线程
  • 如何让两个线程依次执行?

    假设有两个线程,一个是线程 A,另一个是线程 B,两个线程别离依次打印 1-3 三个数字即可。我们来看下代码:

    java; gutter: true">private static void demo1() {
        Thread A = new Thread(new Runnable() {
            @Override
            public void run() {
                printNumber("A");
            }
        });
        Thread B = new Thread(new Runnable() {
            @Override
            public void run() {
                printNumber("B");
            }
        });
        A.start();
        B.start();
    }

    个中的 printNumber(String) 实现如下,用来依次打印 1, 2, 3 三个数字:

    private static void printNumber(String threadName) {
        int i=0;
        while (i++ < 3) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadName + "print:" + i);
        }
    }

    这时我们获得的功效是:

    B print: 1
    A print: 1
    B print: 2
    A print: 2
    B print: 3
    A print: 3

    可以看到 A 和 B 是同时打印的。

    那么,假如我们但愿 B 在 A 全部打印 完后再开始打印呢?我们可以操作 thread.join() 要领,代码如下:

    private static void demo2() {
        Thread A = new Thread(new Runnable() {
            @Override
            public void run() {
                printNumber("A");
            }
        });
        Thread B = new Thread(new Runnable() {
            @Override
            public void run() {
            	System.out.println("B 开始期待 A");
                try {
                    A.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                printNumber("B");
            }
        });
        B.start();
        A.start();
    }

    获得的功效如下:

    B 开始期待 A
    A print: 1
    A print: 2
    A print: 3
    
    B print: 1
    B print: 2
    B print: 3

    所以我们能看到 A.join() 要了解让 B 一直期待直到 A 运行完毕。

    那如何让 两个线程凭据指定方法有序交错运行呢?

    照旧上面谁人例子,我此刻但愿 A 在打印完 1 后,再让 B 打印 1, 2, 3,最后再回到 A 继承打印 2, 3。这种需求下,显然 Thread.join() 已经不能满意了。我们需要更细粒度的锁来节制执行顺序。

    这里,我们可以操作 object.wait() 和 object.notify() 两个要领来实现。代码如下:

    /**
     * A 1, B 1, B 2, B 3, A 2, A 3
     */
    private static void demo3() {
        Object lock = new Object();
        Thread A = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    System.out.println("A 1");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("A 2");
                    System.out.println("A 3");
                }
            }
        });
        Thread B = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    System.out.println("B 1");
                    System.out.println("B 2");
                    System.out.println("B 3");
                    lock.notify();
                }
            }
        });
        A.start();
        B.start();
    }

    打印功效如下:

    A 1
    A waiting…
    
    B 1
    B 2
    B 3
    A 2
    A 3

    正是我们要的功效。

    那么,这个进程产生了什么呢?

    1. 首先建设一个 A 和 B 共享的工具锁 lock = new Object();
    2. 当 A 获得锁后,先打印 1,然后挪用 lock.wait() 要领,交出锁的节制权,软件开发,进入 wait 状态;
    3. 对 B 而言,由于 A 最开始获得了锁,导致 B 无法执行;直到 A 挪用 lock.wait() 释放节制权后, B 才获得了锁;
    4. B 在获得锁后打印 1, 2, 3;然后挪用 lock.notify() 要领,叫醒正在 wait 的 A;
    5. A 被叫醒后,继承打印剩下的 2,3。