JUC中的Condition

239 阅读2分钟

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战

ConditionReentrantLock对象创建,并且可以同时创建多个,Condition接口在使用前必须先调用ReentrantLocklock()方法获得锁,之后调用Condition接口的await()将释放锁,并且在该Condition上等待,直到有其他线程调用Conditionsignal()方法唤醒线程。

案例:

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

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/12 11:13 上午
 */
public class ConditionTest {

    static ReentrantLock lock = new ReentrantLock();
    static Condition condition1 = lock.newCondition();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            lock.lock();
            try {
                System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + "调用await");
                condition1.await();
                System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + "被唤醒");
            } catch (InterruptedException e) {
               e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });

        Thread t2 = new Thread(() -> {
            lock.lock();
            try {
                System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + "调用signal");
                condition1.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });

        t1.setName("t1");
        t1.start();

        TimeUnit.SECONDS.sleep(1);

        t2.setName("t2");
        t2.start();

    }
}

输出结果

1629253423621 t1调用await
1629253424621 t2调用signal
1629253424621 t1被唤醒

当使用Condition.await()方法时,需要先获取Condition对象关联的ReentrantLock的锁,在Condition.await()方法被调用时,当前线程会释放这个锁,并且当前线程会进行等待(处于阻塞状态)。在signal()方法被调用后,系统会从Condition对象的等待队列中唤醒一个线程,一旦线程被唤醒,被唤醒的线程会尝试重新获取锁,一旦获取成功,就可以继续执行了。因此,在signal()被调用后,一般需要释放相关的锁,让给其他被唤醒的线程,让他可以继续执行。

Condition.await()Condition.signal() 在调用时 必须先获取锁再调用 不然会抛出java.lang.IllegalMonitorStateException异常

使用Condition实现精准唤醒

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

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/12 11:13 上午
 */
public class ConditionTest {

    static ReentrantLock lock = new ReentrantLock();
    static Condition condition1 = lock.newCondition();
    static Condition condition2 = lock.newCondition();
    static Condition condition3 = lock.newCondition();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            lock.lock();
            try {
                System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + "调用await");
                condition1.await();
                System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + "被唤醒");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });

        Thread t2 = new Thread(() -> {
            lock.lock();
            try {
                System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + "调用condition1.signal()");
                condition1.signal();
                System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + "调用await");
                condition2.await();
                System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + "被唤醒");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });

        Thread t3 = new Thread(() -> {
            lock.lock();
            try {
                System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + "调用condition2.signal()");
                condition2.signal();
                System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + "调用await");
                condition3.await();
                System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + "被唤醒");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });

        t1.setName("t1");
        t1.start();

        TimeUnit.SECONDS.sleep(1);

        t2.setName("t2");
        t2.start();

        TimeUnit.SECONDS.sleep(1);

        t3.setName("t3");
        t3.start();

        TimeUnit.SECONDS.sleep(1);

        lock.lock();
        try {
            System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + "调用condition3.signal()");
            condition3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

输出结果

1629255550850 t1调用await
1629255551853 t2调用condition1.signal()
1629255551853 t2调用await
1629255551853 t1被唤醒
1629255552856 t3调用condition2.signal()
1629255552856 t3调用await
1629255552857 t2被唤醒
1629255553855 main调用condition3.signal()
1629255553855 t3被唤醒

测试场景是 main线程来唤醒t3线程 t3线程来唤醒t2线程 t2线程来唤醒t1线程