唤醒线程的三种方法

  1. 使用 Object 中的 wait() 方法让线程等待,使用 Object 中的 notify() 方法唤醒线程

    Untitled

    <aside> 💡 wait()notify() 方法必须在 synchronized 代码块中执行;将 notify 放在 wait 之前,程序无法执行

    </aside>

  2. 使用 JUC 包中 Condition 的 await() 方法让线程等待,使用 signal() 方法唤醒线程

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ThreadExample {
        private final Lock lock = new ReentrantLock();
        private final Condition condition = lock.newCondition();
        private boolean isConditionMet = false;
    
        public void waitForCondition() throws InterruptedException {
            lock.lock();
            try {
                while (!isConditionMet) {
                    System.out.println(Thread.currentThread().getName() + " 等待条件满足...");
                    condition.await();  // 等待条件满足
                }
                System.out.println(Thread.currentThread().getName() + " 条件已满足,继续执行!");
            } finally {
                lock.unlock();
            }
        }
    
        public void signalCondition() {
            lock.lock();
            try {
                System.out.println("条件已满足,唤醒等待的线程...");
                isConditionMet = true;
                condition.signal();  // 唤醒等待的线程
            } finally {
                lock.unlock();
            }
        }
    
        public static void main(String[] args) {
            ThreadExample example = new ThreadExample();
    
            // 创建等待线程
            Thread waitingThread = new Thread(() -> {
                try {
                    example.waitForCondition();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "等待线程");
    
            // 创建唤醒线程
            Thread signalingThread = new Thread(() -> {
                try {
                    // 假设需要一些时间来准备条件
                    Thread.sleep(2000);
                    example.signalCondition();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "唤醒线程");
    
            // 启动线程
            waitingThread.start();
            signalingThread.start();
        }
    }
    
  3. LockSupport 类可以阻塞当前线程以及唤醒指定被阻塞的线程

<aside> 💡 必须先等待后唤醒,如果顺序相反,等待会失去作用

</aside>

使用 LockSupport 来唤醒线程

import java.util.concurrent.locks.LockSupport;

public class LockSupportExample {
    static Thread t1, t2;

    public static void main(String[] args) {
        t1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Thread 1 - Iteration " + i);
                if (i == 2) {
                    // 在第三次迭代时阻塞线程t1
                    LockSupport.park();
                }
            }
        });

        t2 = new Thread(() -> {
            try {
                // 让线程t2休眠一段时间
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 在t2执行后,解除t1的阻塞
            System.out.println("Thread 2 - Unparking Thread 1");
            LockSupport.unpark(t1);
        });

        t1.start();
        t2.start();
    }
}
import java.util.concurrent.locks.LockSupport;

public class UnparkBeforeParkExample {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println("Thread 1 - Trying to park");
            LockSupport.park(); // 尝试阻塞,但由于先调用了unpark,因此不会阻塞
            System.out.println("Thread 1 - Resumed after park");
        });

        // 先调用unpark
        System.out.println("Main - Unparking Thread 1");
        LockSupport.unpark(t1);

        // 稍微等待一下,确保unpark先执行
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 再启动线程
        t1.start();
    }
}

由以上两个例子,可以看出:

  1. LockSupport 可以直接使用
  2. unpark() 可以在 park() 之前调用

park() 和 wait() 对比

与 Object 的 wait & notify 相比