JUC并发编程之等待唤醒机制

目录

1. 线程等待唤醒机制

1.1 使用Object的wait()和notify()方法

1.2 使用Condition接口

1.3 使用LockSupport类


1. 线程等待唤醒机制

在JUC(Java Util Concurrent)并发编程中,线程等待唤醒机制是实现线程之间协作和同步的重要手段。这种机制允许一个线程挂起等待某个条件满足后被唤醒,以及另一个线程在满足某个条件后唤醒等待的线程。在Java中,有多种实现线程等待唤醒机制的方式,包括使用Objectwait()notify()方法、Condition接口以及LockSupport类。

1.1 使用Objectwait()notify()方法

Object类是Java中所有类的父类,在多线程编程中,我们可以利用Objectwait()notify()方法实现线程等待唤醒机制。这种方式需要在同步代码块中进行操作,因为wait()notify()方法必须在同步块中调用。

public class WaitNotifyExample {
    public static void main(String[] args) {
        final Object lock = new Object();

        Thread waitingThread = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Waiting thread: Started waiting...");
                try {
                    lock.wait(); // 线程等待,释放锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Waiting thread: Resumed!");
            }
        });

        Thread notifyingThread = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Notifying thread: Started notifying...");
                lock.notify(); // 唤醒等待线程
                System.out.println("Notifying thread: Finished notifying");
            }
        });

        waitingThread.start();
        try {
            Thread.sleep(1000); // 确保等待线程先执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        notifyingThread.start();
    }
}

在上面的示例中,我们创建了两个线程:waitingThreadnotifyingThreadwaitingThread首先获取锁并调用lock.wait(),进入等待状态,并释放了锁。接着,notifyingThread获取锁,调用lock.notify()唤醒了等待线程。注意,wait()notify()方法都必须在synchronized块内部使用,否则会抛出IllegalMonitorStateException

1.2 使用Condition接口

Condition接口是Java并发包(java.util.concurrent.locks)中的一部分,它提供了类似于Objectwait()notify()方法的功能,但更加灵活。可以在一个Lock对象上通过Condition来实现线程的等待和唤醒。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionExample {
    public static void main(String[] args) {
        final Lock lock = new ReentrantLock();
        final Condition condition = lock.newCondition();

        Thread waitingThread = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Waiting thread: Started waiting...");
                condition.await(); // 线程等待
                System.out.println("Waiting thread: Resumed!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });

        Thread notifyingThread = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Notifying thread: Started notifying...");
                condition.signal(); // 唤醒等待线程
                System.out.println("Notifying thread: Finished notifying");
            } finally {
                lock.unlock();
            }
        });

        waitingThread.start();
        try {
            Thread.sleep(1000); // 确保等待线程先执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        notifyingThread.start();
    }
}

在上述示例中,我们使用了ReentrantLock作为锁,通过调用lock.newCondition()创建了一个与该锁关联的Condition实例。然后,等待线程在等待前调用condition.await()进行等待,而唤醒线程通过condition.signal()来唤醒等待的线程。

1.3 使用LockSupport

LockSupport类是Java并发包(java.util.concurrent.locks)中的工具类,它提供了一种基于线程的阻塞和唤醒机制,不需要依赖于特定的对象实例。

LockSupport的实现依赖于每个线程持有的一个许可(permit)。线程调用park()方法时,如果它持有许可,则立即返回;否则,将会阻塞(挂起)。线程调用unpark(Thread thread)方法时,如果线程处于挂起状态且持有许可,则会使其恢复运行。如果线程尚未调用park()方法或之前已经调用过unpark()方法,并且还持有许可,则后续的park()调用将不会阻塞。而Object类实现线程等待唤醒机制中先notify再wait就会一直处于阻塞状态,Condition接口同理。

LockSupport使用了类似信号量的机制,只有一个许可可供线程使用。如果一个线程调用了unpark(Thread thread)方法,而目标线程还没有调用park()方法,那么目标线程在之后调用park()方法时将立即返回,而不会阻塞。

在内部实现上,LockSupport使用了一些底层的Java本地接口(JNI)来实现线程的挂起和恢复。它通过修改线程的内部状态来达到挂起和恢复线程的目的。

import java.util.concurrent.locks.LockSupport;

public class LockSupportExample {
    public static void main(String[] args) {
        Thread waitingThread = new Thread(() -> {
            System.out.println("Waiting thread: Started waiting...");
            LockSupport.park(); // 线程挂起
            System.out.println("Waiting thread: Resumed!");
        });

        Thread notifyingThread = new Thread(() -> {
            System.out.println("Notifying thread: Started notifying...");
            LockSupport.unpark(waitingThread); // 唤醒线程
            System.out.println("Notifying thread: Finished notifying");
        });

        waitingThread.start();
        try {
            Thread.sleep(1000); // 确保等待线程先执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        notifyingThread.start();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_43649937/article/details/132004667