美文网首页
Java - 线程间通信

Java - 线程间通信

作者: sunboximeng | 来源:发表于2018-05-17 11:51 被阅读14次

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

object.wait(), object.notify()

public static void main(String[] args) {

        Object obj = new Object();
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj) {
                    System.out.println(Thread.currentThread().getName() + 
                    ": 调用wait方法,进入无限等待...");
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + 
                    ": 嗯,我醒了。");

                }
            }
        }, "等待线程").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj) {
                    try {
//                        让等待线程睡一会儿
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + 
                    ": 醒醒啊,老哥,别睡了!");
                    obj.notify();
                }
            }
        }, "叫醒线程").start();
    }

输出:

等待线程: 调用wait方法,进入无限等待...
叫醒线程: 醒醒啊,老哥,别睡了!
等待线程: 嗯,我醒了。

没有在同步代码块中,就用锁对象(任意对象都可以是锁对象)调用wait方法就会报运行时异常IllegalMonitorStateException,虽然编译正确(说明方法调用没错误):

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + 
        ": 调用wait方法,进入无限等待...");
        try {
            wait(); //IllegalMonitorStateException
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ": 嗯,我醒了。");
    }
}, "等待线程").start();
利用sleep()方法,令线程休眠时间大于CPU时间片时间实现(效率低):
利用等待唤醒机制实现交替运行:
Thread B print: 1
Thread A print: 1

Thread B print: 2
Thread A print: 2

Thread B print: 3
Thread A print: 3
利用 thread.join() 方法实现线程B等待线程A:
Thread A print: 1
Thread A print: 2
Thread A print: 3

Thread B print: 1
Thread B print: 2
Thread B print: 3
- 利用 object.wait() 和 object.notify() 两个方法来实现线程的中途插入:
Thread A print: 1

Thread B print: 1
Thread B print: 2
Thread B print: 3

Thread A print: 2
Thread A print: 3
利用 CountdownLatch 对象来实现一个线程等待多个线程:
  1. 创建计数器:CountdownLatch countDownLatch = new CountDownLatch(2);
  2. 等待线程:调用 countDownLatch.await() 方法;
  3. 其他线程:调用 countDownLatch.countDown() 方法,该方法会将计数值减小 1;
  4. 当计数器为 0 时,等待线程 里的 countDownLatch.await() 立即退出,继续执行后面的代码。
利用 CyclicBarrier 对象实现线程之间互相等待
  1. 创建计数器:CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
  2. 每个线程准备完毕后,调用 cyclicBarrier.await(),开始等待别人;
  3. 当指定的 同时等待 的线程数都调用了 cyclicBarrier.await();时,意味着这些线程都准备完毕好,然后这些线程才 同时继续执行。
子线程完成某件任务后(通常比较耗时),把得到的结果回传给主线程。

比如,我们利用子线程去计算从 1 加到 100,并把算出的结果返回到主线程。
Runnable接口中的run() 方法在执行完后不会返回任何结果, Callable接口中的call()方法具有返回值。
利用 Callable 接口和 FutureTask 类实现:

private static void doTaskWithResultInWorker() {
    Callable<Integer> callable = new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            System.out.println("Task starts");
            Thread.sleep(1000);
            int result = 0;
            for (int i=0; i<=100; i++) {
                result += i;
            }
            System.out.println("Task finished and return result");
            return result;
        }
    };
    FutureTask<Integer> futureTask = new FutureTask<>(callable);
    new Thread(futureTask).start();
    try {
        System.out.println("Before futureTask.get()");
        //FutureTask 中的 get() 方法会阻塞主线程。如果不希望阻塞主线程,
        //可以考虑利用 ExecutorService,把 FutureTask 放到线程池去管理执行。
        System.out.println("Result:" + futureTask.get());
        System.out.println("After futureTask.get()");
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}

原文链接:wingjay

相关文章

  • 线程间通信剖析——Java进阶

    Java线程间通信剖析 本文将介绍常用的线程间通信工具CountDownLatch、CyclicBarrier和P...

  • 2.Java内存模型

    1.java并发编程的线程间通信及线程间如何同步线程间通信分为:共享内存,消息传递。线程间同步:共享内存是代码指定...

  • Java多线程(2)

    Java多线程(2) 线程间的通信 线程间的通信又称为进程内通信,多个线程实现互斥访问共享资源时会互相发送信号或等...

  • Java - 线程间通信

    涉及到的知识点:thread.join(), object.wait(), object.notify(), Co...

  • Java线程间通信

    涉及到多个线程协同完成某个任务的时候,就用到了线程间通信的相关知识点。这其中涉及到的知识点有:(1)thread....

  • Java 线程间通信

    线程间的交互和通信 一个线程启动另一个线程public static void main(String[] arg...

  • Java 线程间通信

    1. 线程之间如何通信 共享内存(隐式通信) 消息传递(显式通信 wait / notify synchroniz...

  • Java线程<第四篇>:线程间通信

    线程间通信是Java线程必须掌握的课程之一。线程间的通信的前提是,必须要保证线程还活着,可以使用阻塞方法,将线程暂...

  • Java多线程:线程间通信之volatile与sychroniz

    由前文Java内存模型我们熟悉了Java的内存工作模式和线程间的交互规范,本篇从应用层面讲解Java线程间通信。 ...

  • Java线程简介

    本文将介绍Java线程的状态、线程的中断、线程间通信和线程的实现。 线程的状态 Java语言定义了6种不同的线程状...

网友评论

      本文标题:Java - 线程间通信

      本文链接:https://www.haomeiwen.com/subject/oyfbdftx.html