手写连笔王万能驱动-便携式wifi
2023年4月4日发(作者:多玩魔盒好用吗)
Java控制线程执⾏顺序的⼏种⽅法
叙述
通常情况下,线程的执⾏顺序都是随机的,哪个获取到CPU的时间⽚,哪个就获得执⾏的机会。不过实际的项⽬中有时我们会有需要不同的
线程顺序执⾏的需求。借助⼀些java中的线程阻塞和同步机制,我们往往也可以控制多个线程的执⾏顺序。
⽅法有很多种,本篇⽂章介绍⼏种常⽤的。
解决⽅案
利⽤threadjoin实现线程顺序执⾏
⽅法的可以实现如下的效果,就是挂起调⽤join⽅法的线程的执⾏,直到被调⽤的线程执⾏结束。听起来有点绕,举个例⼦解释
下:
假设有t1,t2两个线程,如果在t2的线程流程中调⽤了,那么t2线程将会停⽌执⾏,等待t1执⾏结束后才会继续执⾏。
很显然,利⽤这个机制,我们可以控制线程的执⾏顺序,看下⾯的例⼦:
publicclassControlThreadDemo{
publicstaticvoidmain(String[]args){
ThreadpreviousThread=tThread();
for(inti=0;i<10;i++){
ThreadJoinDemothreadJoinDemo=newThreadJoinDemo(previousThread);
();
previousThread=threadJoinDemo;
}
n("主线程执⾏完毕");
}
}
publicclassThreadJoinDemoextendsThread{
privateThreadpreviousThread;
publicThreadJoinDemo(Threadthread){
usThread=thread;
}
publicvoidrun(){
try{
n("线程:"+tThread().getName()+"等待"+e());
();
}catch(InterruptedExceptione){
tackTrace();
}
n(tThread().getName()+"开始执⾏");
}
}
运⾏结果:
从执⾏结果可以很容易理解,程序运⾏起来之后,⼀共11个线程排好队等着执⾏,排在最前⾯的是main线程,然后依次是t0,t1…。
利⽤CountDownLatch控制线程的执⾏顺序
还是先说下CountDownLatch的⽤法,CountDownLatch是⼀个同步⼯具类,它允许⼀个或多个线程⼀直等待,直到其他线程执⾏完后
再执⾏。借⽤⼀张经典的图:
CountDownLatch提供两个核⼼的⽅法,countDown和await,后者可以阻塞调⽤它的线程,⽽前者每调⽤⼀次,计数器减去1,当计数
器减到0的时候,阻塞的线程被唤醒继续执⾏。
场景1
先看⼀个例⼦,在这个例⼦中,主线程会等有若⼲个⼦线程执⾏完毕之后再执⾏,不过这若⼲个⼦线程之间的执⾏顺序是随机的。
publicclassControlThreadDemo{
publicstaticvoidmain(String[]args)throwsInterruptedException{
CountDownLatchcountDownLatch=newCountDownLatch(5);
List
h(Thread::start);
();
n("主线程执⾏完毕");
}
}
publicclassCountDownDemoimplementsRunnable{
privateCountDownLatchcountDownLatch;
publicCountDownDemo(CountDownLatchlatch){
ownLatch=latch;
}
@Override
publicvoidrun(){
n("线程"+tThread().getName()+"开始执⾏");
own();
}
}
输出,
这种场景在实际项⽬中有需要的场景,⽐如我之前看过⼀个案例,⼤概的场景是说需要下载⼀个⼤⽂件,开启多个线程分别下载⽂件的⼀部
分,然后有⼀个线程最后拼接所有的⽂件。我们可以考虑使⽤CountDownLatch来控制并发,使拼接的线程放在最后执⾏。
场景2
这个案例带你了解下利⽤CountDownLatch控制⼀组线程⼀起执⾏。就好像在运动场上,教练的发令枪⼀响,所有运动员⼀起跑。我们⼀
般在模拟线程并发执⾏的时候会⽤到这种场景。
我们把场景1的代码稍微改造⼀下,
publicclassControlThreadDemo{
publicstaticvoidmain(String[]args)throwsInterruptedException{
CountDownLatchreadyLatch=newCountDownLatch(5);
CountDownLatchrunningLatchWait=newCountDownLatch(1);
CountDownLatchcompleteLatch=newCountDownLatch(5);
List
h(Thread::start);
();//等待发令
own();//发令
();//等所有⼦线程执⾏完
n("主线程执⾏完毕");
}
}
publicclassCountDownDemo2implementsRunnable{
privateCountDownLatchreadyLatch;
privateCountDownLatchrunningLatchWait;
privateCountDownLatchcompleteLatch;
publicCountDownDemo2(CountDownLatchreadyLatch,CountDownLatchrunningLatchWait,CountDownLatchcompleteLatch){
atch=readyLatch;
gLatchWait=runningLatchWait;
teLatch=completeLatch;
}
@Override
publicvoidrun(){
own();
try{
();
n("线程"+tThread().getName()+"开始执⾏");
}catch(InterruptedExceptione){
tackTrace();
}finally{
own();
}
}
}
场景3
到这⾥,可能很多⼈会想问,利⽤CountDownLatch能做到像前⾯控制多个线程按照⼀个固定的先后顺序执⾏吗?
⾸先我要说,⽤CountDownLatch实现这种场景确实不多见,不过也不是不可以做。请继续看场景3。
publicclassControlThreadDemo{
publicstaticvoidmain(String[]args)throwsInterruptedException{
CountDownLatchfirst=newCountDownLatch(1);
CountDownLatchprev=first;
for(inti=0;i<10;i++){
CountDownLatchnext=newCountDownLatch(1);
newCountDownDemo3(prev,next).start();
prev=next;
}
own();
}
}
publicclassCountDownDemo3extendsThread{
privateCountDownLatchprev;
privateCountDownLatchnext;
publicCountDownDemo3(CountDownLatchprev,CountDownLatchnext){
=prev;
=next;
}
@Override
publicvoidrun(){
try{
();
(1000);//模拟线程执⾏耗时
n("线程"+tThread().getName()+"开始执⾏");
}catch(InterruptedExceptione){
tackTrace();
}finally{
own();
}
}
}
输出,
代码也不难理解,for循环⾥把10个线程串联起来,排好队等着执⾏。排在最前⾯的线程t1在等first这个计数器countDown,然后t1开始
执⾏,执⾏完调⽤⾃⼰的next计数器countDown以唤醒下⼀个,依次类推。
利⽤newSingleThreadExecutor控制线程的执⾏顺序
java的Executors线程池平时⼯作中⽤得很多了,JAVA通过Executors提供了四种线程池,单线程化线程池
(newSingleThreadExecutor)、可控最⼤并发数线程池(newFixedThreadPool)、可回收缓存线程池(newCachedThreadPool)、⽀持定
时与周期性任务的线程池(newScheduledThreadPool)。
顾名思义,newSingleThreadExecutor线程池只有⼀个线程。它存在的意义就在于控制线程执⾏的顺序,保证任务的执⾏顺序和提交顺序
⼀致。其实保证顺序执⾏的原理也很简单,因为总是只有⼀个线程处理任务队列上的任务,先提交的任务必将被先处理。
废话不多说,上代码。
publicstaticvoidmain(String[]args)throwsInterruptedException{
finalExecutorServiceexecutorService=gleThreadExecutor();
for(inti=0;i<5;i++){
finalintindex=i;
e(newRunnable(){
@Override
publicvoidrun(){
tThread().setName("thread-"+index);
n("线程:"+tThread().getName()+"开始执⾏");
try{
(1000);
}catch(InterruptedExceptione){
tackTrace();
}
}
});
}
ermination(30,S);
wnNow();
}
输出,
更多推荐
countdown下载
发布评论