当前位置: 首页 > 后端技术 > Java

关于线程的执行顺序,可能真的就是你想的那样

时间:2023-04-02 00:18:39 Java

摘要:今天我们就来看看线程是怎么执行的,顺序是怎样的?本文分享自华为云社区《线程的执行顺序与你想的不一样!!》,作者:冰河。1、线程的执行顺序是不确定的。当调用Thread的start()方法启动一个线程时,线程的执行顺序是不确定的。也就是说,在同一个方法中,连续创建多个线程后,线程的start()方法的调用顺序并不能决定线程的执行顺序。例如,在这里,看一个简单的示例程序,如下所示。packageio.binghe.concurrent.lab03;/***@authorbinghe*@version1.0.0*@description线程的顺序,直接调用Thread.start()方法不能保证线程的执行顺序*/publicclassThreadSort01{publicstaticvoidmain(String[]args){Threadthread1=newThread(()->{System.out.println("thread1");});线程thread2=newThread(()->{System.out.println("thread2");});线程thread3=newThread(()->{System.out.println("thread3");});thread1.start();thread2.start();线程3。开始();}}在ThreadSort01类中创建三个不同的线程,thread1、thread2和thread3,然后在program()方法中依次调用thread1.start()、thread2.start()和thread3.start分别启动三个不同的线程。那么,问题来了,线程的执行顺序是按照thread1、thread2、thread3的顺序执行的吗?运行ThreadSort01的main方法,结果如下。再次运行thread1thread2thread3时,结果如下。第三次运行thread1thread3thread2时,结果如下。thread2thread3thread1可以看出每次程序运行时线程的执行顺序可能都不一样。线程启动的顺序并不能决定线程执行的顺序。二、如何保证线程的执行顺序1、保证线程执行顺序的一个简单例子在实际的业务场景中,有时候,后启动的线程可能需要依赖先启动的线程来完成执行才能正确执行线程中的业务逻辑。此时,需要保证线程的执行顺序。那么如何保证线程的执行顺序呢?可以使用Thread类中的join()方法来保证线程的执行顺序。例如下面的测试代码。packageio.binghe.concurrent.lab03;/***@authorbinghe*@version1.0.0*@description线程的顺序,Thread.join()方法可以保证线程的执行顺序*/publicclassThreadSort02{publicstaticvoidmain(String[]args)throwsInterruptedException{Threadthread1=newThread(()->{System.out.println("thread1");});Threadthread2=newThread(()->{System.out.println("thread2");});线程thread3=newThread(()->{System.out.println("thread3");});thread1.start();//实际上是让主线程等待子线程执行完成thread1.join();thread2.start();thread2.join();thread3.start();thread3.join();调用线程的join()方法被添加到该方法的下面。此时,运行ThreadSort02类,结果如下。再次运行thread1thread2thread3时,结果如下。第三次运行thread1thread2thread3时,结果如下。Thread1thread2thread3可以看到每次运行的结果都是一样的,所以使用Thread的join()方法可以保证线程执行的顺序。2、join方法如何保证线程的执行顺序既然Thread类的join()方法可以保证线程的执行顺序,那我们就来看看Thread类的join()方法是什么。进入Thread的join()方法,如下图。publicfinalvoidjoin()throwsInterruptedException{join(0);}可以看到join()方法在同一个类中调用了参数化的join()方法,并传递了参数0。继续往下看代码如图以下。publicfinalsynchronizedvoidjoin(longmillis)throwsInterruptedException{longbase=System.currentTimeMillis();现在长=0;if(millis<0){thrownewIllegalArgumentException("超时值为负数");}if(millis==0){while(isAlive()){wait(0);}}else{while(isAlive()){longdelay=millis-now;如果(延迟<=0){中断;}等待(延迟);现在=System.currentTimeMillis()-基础;}}}可以看到将long类型参数的join()方法修改为synchroinzed,表示该方法只能同时被一个实例或方法调用。由于传入的参数为0,程序会进入如下代码逻辑。如果(millis==0){而(isAlive()){等待(0);}}首先,在代码中使用一个while循环判断当前线程是否已经启动并处于活动状态。如果已经启动并且处于活动状态,则调用同一个类中的wait()方法,并传入参数0。继续跟进wait()方法如下图。publicfinalnativevoidwait(longtimeout)throwsInterruptedException;可以看到,wait()方法是一个本地方法,通过JNI调用JDK的底层方法,让线程等待执行完成。需要注意的是,当线程的wait()方法被调用时,主线程会处于等待状态,等待子线程执行完毕再向下执行。也就是说,在ThreadSort02类的main()方法中,调用子线程的join()方法会阻塞main()方法的执行。子线程执行完成后,main()方法会继续向下执行,启动第二个子线程执行子线程的业务逻辑,依次类推。点击关注,第一时间了解华为云的新鲜技术~