您的当前位置:首页Java线程等待、睡眠、停止(wait、join、yield、I

Java线程等待、睡眠、停止(wait、join、yield、I

2024-12-14 来源:哗拓教育
  1. wait、notify机制通常用于等待机制的实现,调用wait进入等待状态,需要的时候调用notify或notifyAll唤醒等待的线程继续执行;wait会释放对象锁。(wait()、notify()、notifyAll()必须放在synchronized block中)
 public static void waitAndNotifyAll() {
        System.out.println("主线程运行");
        Thread thread = new WaitThread();
        thread.start();
        long startTime = System.currentTimeMillis();
        try {
            synchronized (sLockObject) {
                System.out.println("主线程等待");
                sLockObject.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long timeMs = System.currentTimeMillis() - startTime;
        System.out.println("等待耗时:" + timeMs);
    }

    static class WaitThread extends Thread {
        @Override
        public void run() {
            super.run();
            System.out.println("子线程正在运行... " + Thread.currentThread().getName());
            synchronized (sLockObject) {
                try {
                    Thread.sleep(3000);
                    sLockObject.notifyAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

waitAndNotifyAll函数中sLockObject的wait函数使得主线程进入了等待状态,WaitThread的run函数睡眠了3秒钟后调用了sLockObject的notifyAll函数,此时正在等待的主线程就会被唤醒。
注:wait方法配合while循环(循环条件控制是否真的唤醒)使用可以避免notify以及notifyAll的错误唤醒,是正确以及推荐的做法。


wait执行日志.png
  1. Thread的静态函数sleep()是用于实现线程睡眠的,sleep()不会释放对象锁。

  2. 上面的部分十分直观,join的作用就不那么直观了;join函数的意思是阻塞当前调用join函数所在的线程,直到接收线程执行完毕之后再继续。

/**
     * join()
     * 阻塞当前调用join函数时所在的线程
     * 直到接收到线程执行完毕之后再继续
     */
    private void initJoin() {
        WaitThread waitThread1 = new WaitThread();
        WaitThread waitThread2 = new WaitThread();

        waitThread1.start();
        System.out.println("启动线程1");
        try {
            // 调用waitThread1线程的join函数,主线程会阻塞到waitThread1执行完成
            waitThread1.join();
            System.out.println("启动线程2");
            waitThread2.start();
            // 调用waitThread2线程的join函数,主线程会阻塞到waitThread2执行完成
            waitThread2.join();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("主线程继续执行");
    }
//--------------------
 class WaitThread extends Thread {
        @Override
        public void run() {
            super.run();
            System.out.println("子线程正在运行... " + Thread.currentThread().getName());
            synchronized (sLockObject) {
                try {
                    Thread.sleep(3000);
                    sLockObject.notifyAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

上面的逻辑为,启动线程1等待线程1执行完成、启动线程2、等待线程2执行完成、继续执行主线程的代码。


join执行日志.png
  1. yield()作用是主动让出当前线程的执行权,其他线程能否优先执行就看各个线程的状态了。

  2. 当一个线程运行时,另一个线程调用该线程的interrupt()方法来中断他,注意interrupt方法只是在目标线程中设置一个标志,表示线程已经中断,需要注意如果只单纯调用interrupt方法,线程是不会中断的,应该这样:

public class StopRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("StopRunnable 开始...");
        try {
            Thread.sleep(10000);
            System.out.println("StopRunnable try中..."); 
        } catch (InterruptedException e) {
            e.printStackTrace();
            //处理完中断异常后,返回到run()方法入口
            System.out.println("StopRunnable 强制停止...");
            //如果没有return,线程不会实际被中断,它会继续打印下面的信息 
            return;
        }
        System.out.println("StopRunnable 结束...");
    }
}

调用目标线程的interrup方法后,目标线程就会抛InterruptedException异常,捕获到异常后return,利用异常+return的方式实现了线程的停止。

interrup执行日志.png

参考资料:

  1. Android开发进阶 从小工到专家
  2. 线程中断.md

有蛮久没更新文章了,最近一直在忙自己的事情,欢迎各位小伙伴一起讨论。

显示全文