Java~源码对比方法join(long)与sleep(long), 解决join()后面代码提前运行的原因

    科技2026-04-05  10

    文章目录

    sleep(long)源码join(long)源码小结join()后面代码提前运行的原因

    sleep(long)源码

    //native关键字说明其修饰的方法是一个原生态方法, //方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中。 //Java语言本身不能对操作系统底层进行访问和操作,但是可以通过JNI接口调用其他语言来实现对底层的访问。 public static native void sleep(long millis) throws InterruptedException;

    join(long)源码

    public final synchronized void join(long millis) throws InterruptedException { //获取当前时间 long base = System.currentTimeMillis(); long now = 0; //判断等待时间是否合法 不合法抛出异常 if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { //如果等于0判断当前线程是否存在, 如果存活就释放锁, 0秒后再去重新争取锁 while (isAlive()) { wait(0); } } else { //如果等待时间大于0 判断当前线程是否存活 while (isAlive()) { //获得要等待时间 long delay = millis - now; if (delay <= 0) { //如果等待的时间小于0就结束 break; } //等还需要等待就释放锁,等delay秒后再去重新争取锁 wait(delay); now = System.currentTimeMillis() - base; } } }

    小结

    方法join(long)的功能在内部是使用wait(long)方法来实现的,所以join(long)方法具有释放锁的特点。从源代码中可以了解到,当执行wait(long)方法后,当前线程的锁被释放,那么其他线程就可以调用此线程中的同步方法了。而Thread.sleep(long)方法却不释放锁。

    join()后面代码提前运行的原因

    代码演示 public class ThreadA extends Thread { private final Thread b; public ThreadA(Thread b, String name) { this.b = b; this.setName(name); } @Override public void run() { synchronized (b) { System.out.println(this.getName() + " 开始: " + System.currentTimeMillis()); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.getName() + " 结束: " + System.currentTimeMillis()); } } } public class ThreadB extends Thread { public ThreadB(String name) { this.setName(name); } @Override synchronized public void run() { System.out.println(this.getName() + " 开始: " + System.currentTimeMillis()); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.getName() + " 结束: " + System.currentTimeMillis()); } } public class Run { public static void main(String[] args) throws InterruptedException { ThreadB threadB = new ThreadB("B"); ThreadA threadA = new ThreadA(threadB, "A"); threadA.start(); threadB.start(); threadB.join(2000); System.out.println(Thread.currentThread().getName() + " 结束" + System.currentTimeMillis()); } } 运行结果 所以可以完全确定地得出一个结论:方法join(2000)大部分是先运行的,也就是先抢到ThreadB的锁,然后快速进行释放。看一下运行结果的解释: 1 ) b.join(2000)方法先抢到B锁,然后将B锁进行释放; 2 )ThreadA抢到锁,打印ThreadA 开始并且sleep(5000); 3 ) ThreadA打印ThreadA 结束,并释放锁; 4)这时join(2000)和ThreadB争抢锁,而join(2000)再次抢到锁,发现时间已过,释放锁后打印main end; 5 )ThreadB抢到锁打印ThreadB 开始; 6)5秒之后再打印ThreadB 结束。
    Processed: 0.013, SQL: 12