zoukankan      html  css  js  c++  java
  • java多线程之间的通信

    目的

    • 如何让两个线程依次执行?
    • 那如何让 两个线程按照指定方式有序交叉运行呢?
    • 四个线程 A B C D,其中 D 要等到 A B C 全执行完毕后才执行,而且 A B C 是同步运行的
    • 三个运动员各自准备,等到三个人都准备好后,再一起跑
    • 子线程完成某件任务后,把得到的结果回传给主线程

    1.如何让两个线程依次执行?

        public static void main(String[] args) {
            demo1();
            /*
            结果:  t1>>pirnt:1
                   t2>>pirnt:1
                   t2>>pirnt:2
                   t1>>pirnt:2
                   t1>>pirnt:3
                   t2>>pirnt:3
            */
            demo1_1();
            /*
            结果:
                t1>>pirnt:1
                t1>>pirnt:2
                t1>>pirnt:3
                t2>>pirnt:1
                t2>>pirnt:2
                t2>>pirnt:3
            */
        }
         
        public static void demo1() {
            // 线程一
            final Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    printNumber("t1");
                }
            });
        
            // 线程二
            final Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    printNumber("t2");
                }
            });
        
            // 启动线程
            t1.start();
            t2.start();
        }
        
        public static void demo1_1() {
            // 线程一
            final Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    printNumber("t1");
                }
            });
        
            // 线程二
            final Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    // 等到线程一执行完,再执行线程二
                    try {
                        t1.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    printNumber("t2");
                }
            });
        
            // 启动线程
            t1.start();
            t2.start();
        }
        
        /**
         * 线程调用的方法
         * @param threadName
         */
        public static void printNumber(String threadName) {
            int i = 0;
            while (i++ < 3) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        
                System.out.println(threadName+">>pirnt:"+i);
            }
        }
    

    2. 那如何让 两个线程按照指定方式有序交叉运行呢?

    这里可以使用同一个锁控制,然后调用wait()方法,和notify()方法
    线程一打印1,然后线程二打印1,2,3 线程一在打印2,3

        public static void demo2() {
                // 创建一个对象,用来作为锁
                final Object objLock = new Object();
        
                //线程一
                Thread t1 = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        // 同步代码块
                        synchronized (objLock){
                            System.out.println("t1>>print:1");
                            try {
                                objLock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            // 线程二执行完,唤醒线程一
                            System.out.println("t1>>print:2");
                            System.out.println("t1>>print:3");
                        }
                    }
                });
        
                // 线程二
                Thread t2 = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        synchronized (objLock) {
                            // 线程二输出内容
                            System.out.println("t2>>print:1");
                            System.out.println("t2>>print:2");
                            System.out.println("t2>>print:3");
                            // 唤醒wait中的线程
                            objLock.notify();
                        }
                    }
                });
        
                // 启动线程
                t1.start();
                t2.start();
        
            }
            
         结果:
         t1>>print:1
         t2>>print:1
         t2>>print:2
         t2>>print:3
         t1>>print:2
         t1>>print:3
    

    3.四个线程 A B C D,其中 D 要等到 A B C 全执行完毕后才执行,而且 A B C 是同步运行的

    1. 创建一个计数器,设置初始值,CountdownLatch countDownLatch = new CountDownLatch(2);
    2. 在 等待线程 里调用 countDownLatch.await() 方法,进入等待状态,直到计数值变成 0;
    3. 在 其他线程 里,调用 countDownLatch.countDown() 方法,该方法会将计数值减小 1;
    4. 当 其他线程 的 countDown() 方法把计数值变成 0 时,等待线程 里的 countDownLatch.await() 立即退出,继续执行下面的代码。
      CountDownLatch 适用于一个线程去等待多个线程的情况。
        public static void runDAfterABC() {
                // 定义计数器的计数值
                int worker = 3;
                // 创建计数器
                final CountDownLatch countDownLatch = new CountDownLatch(worker);
        
                // 创建线程D
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("D线程等待ABC线程运行。。。。");
                        try {
                            // 线程等待
                            countDownLatch.await();
                            System.out.println("ABC线程运行完,D线程运行");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
        
                // 创建ABC线程
                for (char threadName='A'; threadName<='C'; threadName++) {
                    // char转换为String
                    final String tN = String.valueOf(threadName);
        
                    //创建线程
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println("线程"+tN+"运行中。。");
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println("线程"+tN+"结束");
                            // 计数器减一
                            countDownLatch.countDown();
                        }
                    }).start();
                }
            }
            
            结果:
            
            D线程等待ABC线程运行。。。。
            线程A运行中。。
            线程C运行中。。
            线程B运行中。。
            线程A结束
            线程C结束
            线程B结束
            ABC线程运行完,D线程运行
    


    4. 线程 A B C 各自开始准备,直到三者都准备完毕,然后再同时运行

    1. 先创建一个公共 CyclicBarrier 对象,设置 同时等待 的线程数,CyclicBarrier cyclicBarrier = new CyclicBarrier(3);

    2)这些线程同时开始自己做准备,自身准备完毕后,需要等待别人准备完毕,这时调用 cyclicBarrier.await(); 即可开始等待别人;

    3) 当指定的 同时等待 的线程数都调用了 cyclicBarrier.await();时,意味着这些线程都准备完毕好,然后这些线程才 同时继续执行。

        public static void runABCWhenAllReady() {
                // 定义运行线程数
                int runner = 3;
        
                // 创建CyclicBarrier 对象
                final CyclicBarrier cyclicBarrier = new CyclicBarrier(runner);
                // 创建随机数类,产生准备时间
                final Random random = new Random();
                // 创建线程
                for (char threadName='A'; threadName <= 'C'; threadName++) {
                    final String tN = String.valueOf(threadName);
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            // 随机生成准备时间
                            long prepareTime = random.nextInt(1000)+100;
                            System.out.println("线程"+tN+"准备中。。");
        
                            try {
                                Thread.sleep(prepareTime);
                                System.out.println("线程"+tN+"准备完成,等待其他线程!");
                                // 线程准备完毕
                                cyclicBarrier.await();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            } catch (BrokenBarrierException e) {
                                e.printStackTrace();
                            }
                            // 所有线程准备好后,运行
                            System.out.println("线程"+tN+"运行中。。");
                        }
                    }).start();
                }
            }
            
            结果:
            线程A准备中。。
            线程B准备中。。
            线程C准备中。。
            线程A准备完成,等待其他线程!
            线程C准备完成,等待其他线程!
            线程B准备完成,等待其他线程!
            线程A运行中。。
            线程B运行中。。
            线程C运行中。。
    

    5. 子线程运行完后,将结果返回给主线程

    实现接口类:Callable,在 v call()方法中编写运行代码

    将结果返回主线程,使用 FutureTask 类的 get 方法,将数据传回去,

    get方法会阻塞线程,然后call方法执行

        public static void doTaskWithResultInWorker() {
                // 创建Callable对象
                Callable<Integer> callable = new Callable<Integer>() {
                    @Override
                    public Integer call() throws Exception {
                        // 创建任务
                        System.out.println("任务开始");
                        int result = 0;
                        for (int i=0; i<=100; i++) {
                            result += i;
                        }
                        System.out.println("任务结束,返回结果");
                        // 返回结果
                        return result;
                    }
                };
        
                // 创建FutureTask,获取返回值
                FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
                // 启动线程
                new Thread(futureTask).start();
        
                // 线程阻塞,获取返回值
                try {
                    System.out.println("结果:"+futureTask.get());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
            
            结果:
            任务开始
            任务结束,返回结果
            结果:5050
    
  • 相关阅读:
    css常见布局问题
    jsonp原理及同源策略
    执行webpack-dev-server时,提示端口被占用。
    PHP中的<<<运算符
    PHP中的字符串类型
    数据库系统的结构
    HDU 2516 取石子游戏
    常用MySql命令列选
    mysql简单语句
    微信小程序-循环
  • 原文地址:https://www.cnblogs.com/tester-ggf/p/12434984.html
Copyright © 2011-2022 走看看