• Java多线程--wait和join


    首先从公司一道笔试题开始

     1 package test;
     2 
     3 public class Test implements Runnable {
     4 
     5     public int i = 0;
     6 
     7     @Override
     8     public void run() {
     9         try {
    10             Thread.sleep(1000);
    11         } catch (InterruptedException e) {
    12             // TODO Auto-generated catch block
    13             e.printStackTrace();
    14         }
    15         i = 10;
    16     }
    17 
    18     public static void main(String[] args) {
    19         try {
    20             Test t = new Test();
    21             Thread th = new Thread(t);
    22             th.start();
    23             th.join();
    24             System.out.println(t.i);
    25         } catch (Exception ex) {
    26 
    27         }
    28 
    29     }
    30 }

     问23行代码怎么写,才能让24行打印出10?

    不少笔试者会选t.wait()或者th.wait()!

    面试的时候问他为什么,他具体也说不清楚,感觉就是见过这个wait方法,但是wait方法的含义确一知半解。

    wait 是什么意思呢?我举例子啊,比如我想让本线程放弃当前对象锁,说直白点就是让别的对象进入同步块

     1 package test;
     2 
     3 public class Test implements Runnable {
     4 
     5     public Object i = new Object();
     6 
     7     @Override
     8     public void run() {
     9         synchronized (i) {
    10             System.out.println(Thread.currentThread().getName()+"enter ");
    11 //            i.notify();
    12             try {
    13                 i.wait();
    14             } catch (InterruptedException e) {
    15                 // TODO Auto-generated catch block
    16                 e.printStackTrace();
    17             }
    18             System.out.println(Thread.currentThread().getName()+"out ");
    19         }
    20     }
    21 
    22     public static void main(String[] args) {
    23         try {
    24             Test t = new Test();
    25             Thread th1 = new Thread(t);
    26             Thread th2 = new Thread(t);
    27             th1.start();
    28             th2.start();
    29             
    30             
    31         } catch (Exception ex) {
    32 
    33         }
    34 
    35     }
    36 }

    如上例,你会看到输出

    Thread-0enter
    Thread-1enter

    不会看到

    Thread-1out
    Thread-0out

    因为Thread-0 先获得了Object i 锁,然后运行到13行,释放了该锁,

    这个时候Thread-1就获得了Object i 锁,进入了同步代码块,然后同样运行13行,也释放了该锁。

    这个时候在有两个线程Thread-0和Thread-1等待获得Object i 锁,由于代码中没有调用i.notifyAll(),所以这个程序永远不会退出。

    但是如果打开注释11行,那么你将会看到结果

    Thread-0enter
    Thread-1enter
    Thread-0out

    因为Thread-0 先获得了Object i 锁,然后运行到13行,释放了该锁,

    这个时候Thread-1就获得了Object i 锁,进入了同步代码块,运行到11行,i.notify(),

    那么这个意思就是说别的等待i锁的线程可以唤醒了,一旦我(Thread-1)释放锁(13行调用wait()),那么Thread-0就可以获得i锁继续执行了。

    此程序中没有在Thread-1 释放i锁(wait())之后notify,所以永远不会看到Thread-1out

    再回到这个题目,我们的意思是让主线程等待所有子线程执行完毕 ,再执行。更何况笔试题中没有锁对象。更别提wait()了。

    所以,此处应该用th.join();   Thread.join()方法会阻塞主线程继续向下执行。

     1 public class TestThread extends Thread  
     2 {  
     3     private CountDownLatch countDownLatch;  
     4           
     5     public TestThread(CountDownLatch countDownLatch)  
     6     {  
     7         this.countDownLatch = countDownLatch;  
     8     }  
     9 
    10     public void run()  
    11     {  
    12         System.out.println(this.getName() + "子线程开始");  
    13         try  
    14         {  
    15             // 子线程休眠五秒  
    16             Thread.sleep(5000);  
    17         }  
    18         catch (InterruptedException e)  
    19         {  
    20             e.printStackTrace();  
    21         }
    22 
    23         System.out.println(this.getName() + "子线程结束");
    24           
    25         // 倒数器减1
    26         countDownLatch.countDown();
    27     }
    28 }
     1 public class Main
     2 {
     3     public static void main(String[] args)
     4     {
     5         long start = System.currentTimeMillis();
     6         
     7         // 创建一个初始值为5的倒数计数器
     8         CountDownLatch countDownLatch = new CountDownLatch(5);
     9         for(int i = 0; i < 5; i++)
    10         {
    11             Thread thread = new TestThread(countDownLatch);
    12             thread.start();
    13         }
    14         
    15         try
    16         {
    17             // 阻塞当前线程,直到倒数计数器倒数到0
    18             countDownLatch.await();
    19         }
    20         catch (InterruptedException e)
    21         {
    22             e.printStackTrace();
    23         }
    24         
    25         long end = System.currentTimeMillis();
    26         System.out.println("子线程执行时长:" + (end - start));
    27     }
    28 }
  • 相关阅读:
    js递归函数和call()
    前端常用
    整理项目中用到的angularjs及其他js代码
    体验设计真的是让一切简单到极致吗?
    iview table中利用render动态循环输出
    Vue+iview在render函数中添加Poptip提示操作
    jQuery
    外部js调用vue实例方法
    es6 filter() 数组过滤方法总结
    vue通信、传值的多种方式
  • 原文地址:https://www.cnblogs.com/fengjian/p/4631724.html
Copyright © 2020-2023  润新知