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

    最近在研究java多线程,这篇文章主要是介绍一些线程之间的通信:

    1:join 的方式,一个线程等待另一个线程执行完毕后在执行,可以控制线程执行的顺序;

    场景:B线程要在A线程完成后才开始任务:

    不做任何控制的情况下的线程代码如下:

    @Test
        public void threadTest4() throws InterruptedException, ExecutionException {
    //        线程A
            final Thread threadA = new Thread(new Runnable() {
                @Override
                public void run() {
                    printNum("线程A");
                }
            });
    //        线程B
            Thread threadB= new Thread(new Runnable() {
                @Override
                public void run() {
    //                try {
    //                    threadA.join();
    //                } catch (InterruptedException e) {
    //                    e.printStackTrace();
    //                }
                    printNum("线程B");
                }
            });
    
            threadA.start();
            threadB.start();
            Thread.sleep(1000);
        }
    private void printNum(String threadName){
            int i=0;
            while (i++<3){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(threadName+"打印"+i);
            }
        }
    

    这样打印出来的效果如下:

    线程B打印1
    线程A打印1
    线程B打印2
    线程A打印2
    线程B打印3
    线程A打印3
    

    这样不能保证 B 线程在A 线程执行完之后再执行;可以通过 join 方法来实现我们的需求: 当在 B 线程调用 A线程的join 方法 则会 B 线程等待A线程执行完了之后再执行B 线程;将上面注掉的代码解开就行了;

    这样打印出来的效果是:

    线程A打印1
    线程A打印2
    线程A打印3
    线程B打印1
    线程B打印2
    线程B打印3
    

    这样就能保证 B 线程在 A线程执行结束后再执行;

    2:多个线程按照一定的顺序交叉执行:

    场景:A 线程执行打印完 1 2 后 B 线程再执行打印 1 2 3 

    这样的场景需要使用 锁的等待和唤醒的机制来实现,代码实现如下:  需要用到两个方法 wait  和 notify 方法  这两个方法都是 Object对象的方法;

    @Test
        public void threadTest5() throws InterruptedException, ExecutionException {
            final Object o=new Object();
            Thread threadA = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (o){
                        System.out.println("线程A 打印 1");
                        try {
                            o.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("线程A 打印 2");
                        System.out.println("线程A 打印 3");
                    }
    
                }
            });
    
            Thread threadB = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (o){
                        System.out.println("线程B 打印 1");
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("线程B 打印 2");
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("线程B 打印 3");
                        o.notify();
                    }
    
                }
            });
            threadA.start();
            threadB.start();
            Thread.sleep(1000);
        }
    

    下面分析这段代码的执行顺序:

    1:创建对象锁 

    final Object o=new Object();

    2:A 首先获得对象锁的控制权;

    3:A 调用  wait 方法 让出对象锁的控制权:

    o.wait();

    4:B 线程获得对象锁的控制权:

    B线程的业务代码处理完之后 调用 notify 方法,唤醒 正在 wait  的线程 然后结束B线程的同步代码块,

    5:A 线程获取到了对象锁的控制权后执行自己的业务逻辑;

    这样就满足我们需要的场景;

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

    通过 调用对象锁的 notify 和 wait 方法可以满足线程的执行顺序 但是线程是一次执行的,不能同时进行;

    需要同步进行有需要进行控制线程的执行顺序则可以使用 线程计数器来实现  

    代码如下:

    @Test
        public void threadTest1() throws InterruptedException {
            int worker = 3;
            System.out.println("计数器的值为:" + worker);
            final CountDownLatch countDownLatch = new CountDownLatch(worker);
            Thread threadD = new Thread(new Runnable() {
                @Override
                public void run() {
    
                    System.out.println("D 线程等待其他线程!");
                    try {
                        countDownLatch.await();
                        System.out.println("其他线程运行结束,D线程开始");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            threadD.start();
    
            for (int i = 0; i < 3; i++) {
    
                final int finalI = i;
                Thread threadA = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName() + finalI + "is working");
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + finalI + "is finish");
                        countDownLatch.countDown();
                    }
                });
                threadA.start();
            }
    
            Thread.sleep(1000);
    
        }
    

      上面代码的执行顺序如下:

    1:创建线程计数器:计数器的计数个数为3;

    2:当D线程开始执行的时候调用计数器的 await 方法,然后等待;

    3:执行 ABC 线程的业务逻辑的处理,在线程的业务逻辑处理之后分别调用 计数器的 数字减1.

    4:当计数器的数值为0 时D线程获得执行权,开始执行;

    4:多线程获取线程处理的返回值:

    代码如下:

    @Test
        public void threadTest3() throws InterruptedException, ExecutionException {
            Callable<Integer> callable = new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    System.out.println("开始任务!!");
                    Thread.sleep(100);
                    int result=0;
                    for (int i = 0; i <100 ; i++) {
                        result +=i;
                    }
                    return result;
                }
            };
            FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
            new Thread(futureTask).start();
            System.out.println("任务获取前");
            System.out.println("任务获取到的结果是:"+futureTask.get());
            System.out.println("任务获取后");
            Thread.sleep(1000);
    
        }

    通过Callable  和 FutureTask 两类可以实现这个功能, 注意 FutureTask  的 get()方法是同步,必须在callable中的call 方法执行结束后;

    
    
    
    
    
    
  • 相关阅读:
    Struts2拦截器
    struts2介绍
    java读写文件大全
    Intent的详细解析以及用法
    sigmoid和softmax的应用意义区别
    C 实现 创建多个txt文件,并以自然数列命名,然后将产生的十进制数据写入txt文档
    k-means原理和python代码实现
    非极大值抑制 NMS
    JetSonNano darknet yolov3工程通过CMakeLists.txt配置编译环境
    C文件 CMakeList.txt编译器配置错误的问题 error:invalid conversion from 'int' to 'LAYER_TYPE' [-fpermissive]....
  • 原文地址:https://www.cnblogs.com/beppezhang/p/8417647.html
Copyright © 2011-2022 走看看