前言
之前没怎么关注到这两个的区别以及源码探讨
后面被某个公司面试问到了,开始查漏补缺
1. wait()
使当前线程等待,直到它被唤醒,通常是通过被通知或被中断,或者直到经过一定的实时时间。
本身属于一个Object 类,查看源代码也可知:public class Object {
查看其源码可知,一共有三个重载的方法,详情源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
//第一个重载函数 public final void wait() throws InterruptedException { wait(0L); }
//第二个重载函数 public final native void wait( long timeoutMillis) throws InterruptedException;
//第三个重载函数 public final void wait( long timeoutMillis, int nanos) throws InterruptedException { if (timeoutMillis < 0 ) { throw new IllegalArgumentException( "timeoutMillis value is negative" ); }
if (nanos < 0 || nanos > 999999 ) { throw new IllegalArgumentException( "nanosecond timeout value out of range" ); }
if (nanos > 0 && timeoutMillis < Long.MAX_VALUE) { timeoutMillis++; }
wait(timeoutMillis); } |
具体实战调用代码如下:
如果执行到了wait函数,在这4秒内,会释放锁,并且暂停线程。如果这四秒内配合notify()可以唤醒并且得到锁,如果没有唤醒,等待其他来竞争。4秒结束后,会默认自动释放锁
当前线程在 Thread.wait()等待过程中,如果Thread结束了,是可以自动唤醒的而且自动释放锁
1 2 3 4 5 6 |
@Override public void run() { synchronized (a) { a.wait( 4000 ); } } |
2. join()
join是Thread类的方法
查看其源码,具体源码如下,三个重载的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
//第一个重载函数 public final synchronized void join( final long millis) throws InterruptedException { if (millis > 0 ) { if (isAlive()) { final long startTime = System.nanoTime(); long delay = millis; do { wait(delay); } while (isAlive() && (delay = millis - TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0 ); } } else if (millis == 0 ) { while (isAlive()) { wait( 0 ); } } else { throw new IllegalArgumentException( "timeout value is negative" ); } }
//第二个重载函数 /*等待该线程死亡的时间最多为毫秒加纳秒。 如果两个参数都为0,则意味着永远等待。 这个实现使用了This的循环。 等待电话以this.isAlive为条件。 当一个线程终止this。 调用notifyAll方法。 建议应用程序不要使用wait、notify或notifyAll on Thread实例。 */ public final synchronized void join( long millis, int nanos) throws InterruptedException {
if (millis < 0 ) { throw new IllegalArgumentException( "timeout value is negative" ); }
if (nanos < 0 || nanos > 999999 ) { throw new IllegalArgumentException( "nanosecond timeout value out of range" ); }
if (nanos > 0 && millis < Long.MAX_VALUE) { millis++; }
join(millis); }
//第三个重载函数 /*等待线程死亡。 此方法的调用与调用的行为完全相同
InterruptedException—如果任何线程中断了当前线程。 当抛出此异常时,当前线程的中断状态将被清除。 */ public final void join() throws InterruptedException { join( 0 ); } |
主要的时间参数逻辑如下:
小于0,抛出异常 等于0,join(A),判断A是否存在,存在才执行操作。该线程执行wait(0)等待,等待A线程执行完后才可结束 大于0,同上,只不过执行的是wait(long millis),等待时间结束后才可继续执行操作
3. sleep()
对比上一个wait函数
sleep(long mills):让出CPU资源,但是不会释放锁资源。 wait():让出CPU资源和锁资源。查看sleep函数的源码,一共有两个重载函数
都是Thread类的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/*根据系统计时器和调度器的精度和准确性, 使当前执行的线程在指定的毫秒数内处于睡眠状态(暂时停止执行)。 线程不会失去任何监视器的所有权。*/ public static native void sleep( long millis) throws InterruptedException;
/*导致当前执行的线程在指定的毫秒数加上指定的纳秒数 (取决于系统计时器和调度器的精度和准确性)内休眠(暂时停止执行)。 线程不会失去任何监视器的所有权。 */ public static void sleep( long millis, int nanos) throws InterruptedException { if (millis < 0 ) { throw new IllegalArgumentException( "timeout value is negative" ); }
if (nanos < 0 || nanos > 999999 ) { throw new IllegalArgumentException( "nanosecond timeout value out of range" ); }
if (nanos > 0 && millis < Long.MAX_VALUE) { millis++; }
sleep(millis); } |
4. yield()
查看yield()函数的源码,一个重载函数
都是Thread类的函数
向调度器暗示当前线程愿意放弃当前对处理器的使用。 调度器可以忽略这个提示。
Yield是一种启发式尝试,旨在改善线程之间的相对进程,否则会过度使用CPU。 它的使用应该与详细的分析和基准测试相结合,以确保它实际上具有预期的效果。
使用这种方法很少是合适的。 它可能用于调试或测试目的,在这些目的中,它可能有助于由于竞争条件而重新生成错误。 在设计并发控制构造(如java.util.concurrent.locks包中的构造)时,它可能也很有用。
1 |
public static native void yield(); |
总的来说,yield函数的功能主要是:
让出CPU调度,暂停线程,但不能由用户指定时间
只能让同优先级有执行机会
5. 总结
wait 暂停该线程,让出cpu,释放锁。(Object类)
join暂停该线程,执行该线程之后才能回到自身的线程运行。(Thread类)
sleep 暂停该线程,让出cpu,不释放锁。(Thread类)
yield 暂停该线程,但是不能由用户制定,只能让同优先级有执行机会。(Thread类)
5.1 wait和join的区别
看完以上的源码以及逻辑代码,再讲讲两者的异同
总的来说
wait函数:让当前线程进入等待状态,wait()会与notify()和notifyAll()方法一起使用。notify为唤醒函数 join函数:等待这个线程结束才能执行自已的线程。它的主要起同步作用,使线程之间的执行从[并行]变成[串行]。线程A中调用了线程B的join()方法时,线程执行过程发生改变:线程A,必须等待线程B执行完毕后,才可以继续执行下去
共同点:
暂停当前的线程 都可以通过中断唤醒不同点在于:
类 | Object类 | Thread类 |
目的 | 线程间通信 | 排序,让其串行通过 |
同步 | 必须要synchronized | 可以不用synchronized |
5.2 wait和sleep的区别
wait():让出CPU资源和锁资源。
sleep(long mills):让出CPU资源,但是不会释放锁资源。
看区别,主要是看CPU的运行机制:
它们的区别主要考虑两点:1.cpu是否继续执行、2.锁是否释放掉。
归根到底:
wait,notify,notifyall 都是Object对象的方法,是一起使用的,用于锁机制,所以会释放锁
而sleep是Thread类,跟锁没关系,不会释放锁
但是两者都会让出cpu资源
以上就是Java四个线程常用函数超全使用详解的详细内容,更多关于Java线程函数的资料请关注其它相关文章!
原文链接:https://blog.csdn.net/weixin_47872288/article/details/123665786
查看更多关于Java四个线程常用函数超全使用详解的详细内容...