前言
在Java中,每个对象都可以调用 Object 的 wait/notify 方法来实现等待/通知机制。而 Condition 接口也提供了类似的方法,也能实现等待唤醒,Condition需要在ReentrantLock下使用,也就是需要上锁和释放锁,否则也会报java.lang.IllegalMonitorStateException
Condition使用
Condition方法
Condition提供await()、signal()、signalAll()方法,其中,await()是让线程等待,signal()是唤醒一个线程,signalAll()是唤醒全部线程,当前线程调用condition.await()方法后,会释放 lock 然后加入到等待队列,直到被 signal/signalAll 方法唤醒
Condition等待唤醒使用
1、await()等待唤醒
ini
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionTest {
public static void main(String[] args) {
final ReentrantLock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
Thread thread1 = new Thread(() -> {
String name = Thread.currentThread().getName();
lock.lock();
try {
System.out.println(name + " <==进入条件队列等待");
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
System.out.println(name + ":线程被唤醒");
}, "aa");
thread1.start();
Thread thread2 = new Thread(() -> {
String name = Thread.currentThread().getName();
lock.lock();
try {
Thread.sleep(5000);
System.out.println(name + ":开始唤醒线程");
} catch (InterruptedException e) {
e.printStackTrace();
}
condition.signalAll();
lock.unlock();
System.out.println(name + ":唤醒结束");
}, "通知线程");
thread2.start();
}
}
输出结果为
signal()只能唤醒一个线程
ini
package cn.com.ut.july.wait;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionTest {
public static void main(String[] args) {
final ReentrantLock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
Thread thread1 = new Thread(() -> {
String name = Thread.currentThread().getName();
lock.lock();
try {
System.out.println(name + " <==进入条件队列等待");
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
System.out.println(name + ":线程被唤醒");
}, "aa");
thread1.start();
Thread thread3 = new Thread(() -> {
String name = Thread.currentThread().getName();
lock.lock();
try {
System.out.println(name + " <==进入条件队列等待");
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
System.out.println(name + ":线程被唤醒");
}, "aa1");
thread3.start();
Thread thread2 = new Thread(() -> {
String name = Thread.currentThread().getName();
lock.lock();
try {
Thread.sleep(5000);
System.out.println(name + ":开始唤醒线程");
} catch (InterruptedException e) {
e.printStackTrace();
}
condition.signal();
lock.unlock();
System.out.println(name + ":唤醒结束");
}, "通知线程");
thread2.start();
}
}
输出结果为
signalAll()唤醒全部线程
ini
package cn.com.ut.july.wait;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionTest {
public static void main(String[] args) {
final ReentrantLock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
Thread thread1 = new Thread(() -> {
String name = Thread.currentThread().getName();
lock.lock();
try {
System.out.println(name + " <==进入条件队列等待");
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
System.out.println(name + ":线程被唤醒");
}, "aa");
thread1.start();
Thread thread3 = new Thread(() -> {
String name = Thread.currentThread().getName();
lock.lock();
try {
System.out.println(name + " <==进入条件队列等待");
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
System.out.println(name + ":线程被唤醒");
}, "aa1");
thread3.start();
Thread thread2 = new Thread(() -> {
String name = Thread.currentThread().getName();
lock.lock();
try {
Thread.sleep(5000);
System.out.println(name + ":开始唤醒线程");
} catch (InterruptedException e) {
e.printStackTrace();
}
condition.signalAll();
lock.unlock();
System.out.println(name + ":唤醒结束");
}, "通知线程");
thread2.start();
}
}
输出结果为
Condition实现三个线程顺序输出
scss
package cn.com.ut.july.wait;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionDemo {
public static void main(String[] args) throws InterruptedException {
ReentrantLock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
new Thread(() -> {
while (true) {
try {
Thread.sleep(500);
System.out.println("A");
lock.lock();
condition2.signal();
condition1.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}).start();
Thread.sleep(100);
new Thread(() -> {
while (true) {
try {
Thread.sleep(500);
System.out.println("B");
lock.lock();
condition3.signal();
condition2.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}).start();
Thread.sleep(100);
new Thread(() -> {
while (true) {
try {
Thread.sleep(500);
System.out.println("C");
lock.lock();
condition1.signal();
condition3.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}).start();
}
}
输出结果为
使用Thread.sleep()是为了保证先start()的线程先启动,以及不输出那么快
总结
Condition的await()和signal()基于Lock,相比于基于Object的wait()和notify()方法,它提供更加灵活的等待通知的机制,并且是基于AQS队列形式,但是在开发过程中,根据自己喜好选择