美文网首页
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 - 线程间通信

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