Java基础day12笔记:多线程(守护线程)|多线程(join
08-多线程(守护线程)
接下来说一下Thread类中的其他方法。
点进去看一看:
我们试一下~
先将它注释掉运行一下:
发现程序停在这里不动了。
我们将它们标记成守护线程:
编译运行:
结束啦。
守护线程其实不是很好理解,其实应该叫做后台线程。我们所能看到的线程都是前台线程,当把某些线程标记成后台后,它就具备了某些含义。
后台线程的特征是:开启后和前台线程一起共同争夺cpu的执行权。
它和前台线程在开启、运行上都没有区别,就结束有区别。
当所有的前台线程都结束后,后台线程会自动结束。有一点依赖前台线程的感觉。
而在这个例子中,主线程是前台线程,前台线程结束后,Thread0和Thread1自动结束。
后台线程就是守护线程,跟着前台线程跑,前台线程挂了,它也就挂了。
总结一下守护线程设置的方法setDaemon:
1,该方法必须在启动线程前调用。
2,当正在运行的线程都是守护线程时,Java虚拟机退出。
09-多线程(Join方法)
再接着看,还是方法~
刚刚讲interrupt方法时,它里面有提到join:
join是什么呢?
点进去看看:
写个例子并运行:
发现几个线程在交替运行。
现在加上join:
编译运行:
我们发现Thread0一直执行到69,之后main和Thread1才交替执行。
所以join是什么意思呢?
主线程读到t1.join();时,叫做t1要申请加入到运行中来。更确切的说,t1要cpu的执行权。此时主线程就把执行权放出来了,给了t1。这时主线程处于了冻结状态。t1执行完之后,主线程才恢复到运行状态中。
join方法有什么用呢?
当我们在进行多线程运算的时候,一个线程在运行过程中,我们可以临时加入另一个线程,让新加入的线程运算完之后,旧的线程再继续运行。
我们再试试,将t1.join()放在下面会发生什么现象。
分析一下:
主线程依次开启了t1、t2线程,当执行到t1.join时,t1就加入了,这个时候主线程就停下来了,冻结了,而t1拿到了执行权,注意,主线程碰到t1是释放了执行权。而此时有两个线程还活着,t1和t2,都具备执行资格,这个时候cpu就对t1和t2交替执行。那主线程什么时候活呢?它要等到t1结束才能活,至于t2是否结束,跟主线程没有关系。如果t1结束了,主线程活了,而t2还没有结束,这时主线程就在跟t2抢执行权。所以,主线程碰到谁的join,它就等谁。
总结一下:
join:
当A线程执行到了B线程的.join()方法时,A就会等待,等B线程都执行完,A才会执行。
join可以用来临时加入线程执行。
还有个问题:
主线程遇到了t1的join,主线程就冻结了,万一t1在运行过程中挂了呢(wait)?
t1只要一wait主线程就挂了。
这个时候为什么interrupt能清除冻结状态呢?它能把主线程的状态清除掉,清除完以后,t1挂着,主线程也能运行,不用为了等t1而死。而强制让它活过来,就会发生异常。(这里有点乱,还要理一理)
10-多线程(优先级&yield方法)
Thread类中有一个方法:
试一下:
我们会看到Thread1,优先级是5,所属的线程组是main。(一般来说,谁开启的这个线程,这个线程所属的线程组就是开启它的那个线程)
当然我们也可以手动设置线程组:
我们只要new一个这个对象,将所需要的线程封装到这个组中就OK。
当然,开发中几乎用不到这个,因为用起来挺麻烦的。所以就不细讲啦。
接下来再说优先级。
优先级代表着抢资源的频率。
优先级越高,则主线程执行它的频率越高。
默认的优先级是5。
如果不喜欢5,可以改,设置优先级的方法:
.那可以调成10000吗(认真脸)?
优先级最高是10级喔。
相邻的优先级其实差别不大,比如5和6,频率都差不多。
而跨度最明显的3个优先级为1,5,10。
所以,还给它们起了名称:
它们都是静态的常量:
我们试一下:
一般运行次数越多,优先级体现的越明显。(当然,即使优先级很高,也不可能一直霸着cpu)
顺便再提一下yeild方法:
试一下:
我们发现Thread0和Thread1在交替执行。
0进去之后,读到Thread.yield(),会主动放弃,让1进来,1读到Thread.yield(),也会主动放弃,让0进来,就这样交替着执行。
这样可以减缓一下线程的运行,可以达到让线程运行的频率都差不多的效果。这个也不是很常用喔。
再来一个例子:
如果前面的循环量级非常高的话,后面的循环几乎就执行不到了。
可是我们学了多线程,当需要几段代码同时运行时,将它们封装到单独的线程中:
这里用了匿名类,因为用它更方便快捷一些。