美文网首页
多个线程等待

多个线程等待

作者: 麦兜的夏天 | 来源:发表于2019-05-31 22:51 被阅读0次

场景一:

假设在一个线程 A 中开启了另一个线程 B,A 线程依赖 B 线程的计算结果,可是直接开启线程后,很有可能 A 线程比 B 线程跑得快,也就是说还没等 B 线程计算出结果,A 线程已经结束了。

  • 存在问题的代码:
public static void main(String[] args) throws Exception {
        Thread parser1 = new Thread(new Runnable() {
            @Override
            public void run() {
                temp temp = new temp();  //temp 对象的 a 属性初始化值为 0
                temp.a += 100;
                System.out.println("parser1 finish");
            }
        });
        parser1.start();
        
        temp temp = new temp();
        System.out.println(temp.a);       
} 

//main 函数属于一个线程,它内部开启了 parser1 这个线程。
打印出的结果是 0 ,而不是 100 。

怎么解决这个问题?
让线程 A 等待着线程 B,直到线程 B 结束之后再继续进行。 只需要在线程 B 开启之后,再调用 join() 方法阻塞线程,就可以了。

  • 改善代码
public static void main(String[] args) throws Exception {
        Thread parser1 = new Thread(new Runnable() {
            @Override
            public void run() {
                temp temp = new temp();
                temp.a += 100;
                System.out.println("parser1 finish");
            }
        });
        parser1.start();
        parser1.join();  //阻塞线程
        
        temp temp = new temp();
        System.out.println(temp.a);       
} 

打印的结果为 100

场景二:

假如在线程 A 里面有 B、C 这几个线程,A 依赖于 B 和 C 线程的执行结果,并且 B 和 C 之间也有某种联系,只有当 B 和 C 在某个固定的点上同步执行,它们才能默契的完成任务。


两个线程之间的关系.png
    public static void main(String[] args) throws Exception {
        //temp 对象的静态变量 a 初始值等于 0
        //如果第一个线程先执行,那么 a 就等于 1
        //这时候再执行第二个线程,a 会变成 100;
        //如果它们的执行顺序正好相反,那么 a 就变成 1 了。
        Thread parser1 = new Thread(new Runnable() {
            @Override
            public void run() {
                temp temp = new temp();
                temp.a += 1;

                try {
                    System.out.println("线程一其余代码被执行");
                    Thread.sleep(5000L);
                    System.out.println("线程一执行结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread parser2 = new Thread(new Runnable() {
            @Override
            public void run() {
                temp temp = new temp();
                temp.a *= 100;

                try {
                    System.out.println("线程二其余代码被执行");
                    Thread.sleep(5000L);
                    System.out.println("线程二执行结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
     
    }
  • 粗糙的方案:
    如果只是简单粗暴的调用 join() 方法让线程阻塞,然后调整他们的执行顺序,其实是一种低效的方法。main 想要拿到最后的计算结果,必须等到两个线程都走完之后。
    public static void main(String[] args) throws Exception {
        Thread parser1 = new Thread(new Runnable() {
            @Override
            public void run() {
                temp temp = new temp();
                temp.a += 1;

                try {
                    System.out.println("线程一其余代码被执行");
                    Thread.sleep(5000L);
                    System.out.println("线程一执行结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread parser2 = new Thread(new Runnable() {
            @Override
            public void run() {
                temp temp = new temp();
                temp.a *= 100;

                try {
                    System.out.println("线程二其余代码被执行");
                    Thread.sleep(5000L);
                    System.out.println("线程二执行结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //parser1 和 parser2 之间是平等的竞争关系,哪个先执行不一定,所以让第二个线程等待1秒
        parser1.start();
        parser2.start();
        parser1.join();
        parser2.join(1000L);
        System.out.println(new temp().a);       
    }
    
//执行结果
线程一其余代码被执行
线程二其余代码被执行
线程一执行结束  
线程二执行结束
(。。。。经历漫长的等待之后。。。。)
100   
  • 优化方案:
    我们可以使用并发包中的 CountDownLatch 来提高效率
    static CountDownLatch c = new CountDownLatch(2);   
    //构造函数中传入参数作为计数器,如果想要等待N个点完成,就传入N

    public static void main(String[] args) throws Exception {
        Thread parser1 = new Thread(new Runnable() {
            @Override
            public void run() {
                temp temp = new temp();
                temp.a += 1;
                c.countDown();    //计数器减一

                try {
                    System.out.println("线程一其余代码被执行");
                    Thread.sleep(5000L);
                    System.out.println("线程一执行结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread parser2 = new Thread(new Runnable() {
            @Override
            public void run() {
                temp temp = new temp();
                c.countDown();   //计数器减二
                temp.a *= 100;

                try {
                    System.out.println("线程二其余代码被执行");
                    Thread.sleep(5000L);
                    System.out.println("线程二执行结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        });

        parser1.start();
        parser2.start();

        c.await();   //计数器等于0时,不再阻塞当前线程

        System.out.println(new temp().a);
    }
    
//执行结果
线程二其余代码被执行
线程一其余代码被执行
100
(。。。。经历漫长的等待之后。。。。)
线程二执行结束
线程一执行结束  

相关文章

  • 计数器:CountDownLatch,CountDownLatc

    计数器 CountDownLatch: 一个线程等待多个线程。 CyclicBarrier:多个线程相互等待,等待...

  • 多个线程等待

    场景一: 假设在一个线程 A 中开启了另一个线程 B,A 线程依赖 B 线程的计算结果,可是直接开启线程后,很有可...

  • Java中的并发工具类

    CountDownLatch等待多线程完成 CountDownLatch允许一个或多个线程等待其他线程完成操作。 ...

  • Java并发-25.并发工具类-CountDownLatch

    等待多线程完成的CountDownLatch CountDownLatch允许一个或者多个线程等待其他线程完成操作...

  • 多线程并发框架使用二

    CountDownlLatch 一个线程和多个线程,等待另外一个线程或者多个线程之后才继续执行,CountDown...

  • 8-Java中的并发工具类

    1.等待多线程完成的CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成操...

  • java并发编程(八)

    1.等待多线程完成的CountDownLatch CountDown允许一个或者多个线程等待其他线程来完成工作。 ...

  • 死锁以及避免方法

    概念: 多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,从而导致两个或者多个线程都在等待对方...

  • 笔记:并发工具类

    1. 等待多线程完成的CountDownLatch 简介 CountDownLatch 允许一个或多个线程等待其他...

  • CountDownLatch

    CountDownLatch允许一个或者多个线程去等待其他线程完成操作。 await() 使当前线程等待直到锁存器...

网友评论

      本文标题:多个线程等待

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