Condition的signal()和Synchronized的notiy()的区别,一文弄懂!
-
Condition中的 await() 方法相当于 Object 的 wait() 方法,Condition中的 signal() 方法相当于Object的notify()方法,Condition中的 signalAll() 相当于Object的notifyAll()方法。不同的是,Object中的这些方法是和同步锁捆绑使用的;而Condition是需要与互斥锁/共享锁捆绑使用的。
-
Condition它更强大的地方在于:能够更加精细的控制多线程的休眠与唤醒。对于同一个锁,我们可以创建多个Condition,在不同的情况下使用不同的Condition。
-
注意:当方法wait()被执行后,锁自动被释放,但执行完notify()方法后,锁不会自动释放。必须执行完notify()方法所在的synchronized代码块后才释放。
那么Notify为什么不能精细控制呢,notify由于是随机唤醒,可能会导致一种情况,即所有线程都被堵塞了,没有哪个线程再去执行notify唤醒。看如下代码:
public class ConditionTest {
//共享变量 标志位 A = 1 B = 2 C = 3
int count = 1;
public static void main(String[] args) {
ConditionTest conditionTest = new ConditionTest();
for (int i = 0 ; i < 10 ;i++) {
new Thread(() -> {
try {
conditionTest.printA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "A").start();
new Thread(() -> {
try {
conditionTest.printB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "B").start();
new Thread(() -> {
try {
conditionTest.printC();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "C").start();
}
}
public synchronized void printA() throws InterruptedException {
while (count != 1){
System.out.println(Thread.currentThread().getName()+"不该此线程操作等待中...");
this.wait();
}
for (int i = 1; i <6 ; i++) {
System.out.println(Thread.currentThread().getName()+"打印"+i);
}
count = 2;
this.notify();
}
public synchronized void printB() throws InterruptedException {
while (count != 2){
System.out.println(Thread.currentThread().getName()+"不该此线程操作等待中...");
this.wait();
}
for (int i = 6; i <11 ; i++) {
System.out.println(Thread.currentThread().getName()+"打印"+i);
}
count = 3;
this.notify();
}
public synchronized void printC() throws InterruptedException {
while (count != 3){
System.out.println(Thread.currentThread().getName()+"不该此线程操作等待中...");
this.wait();
}
for (int i = 11; i <16 ; i++) {
System.out.println(Thread.currentThread().getName()+"打印"+i);
}
count = 1;
this.notify();
}
}
A打印1
A打印2
A打印3
A打印4
A打印5 //A执行到这里后实现notify()
A不该此线程操作等待中... //不满足while条件A堵塞
C不该此线程操作等待中... //不满足while条件 此时A和C在堵塞队列中
B打印6
B打印7
B打印8
B打印9
B打印10 //B执行notify(),正好B不满足while条件,堵塞
B不该此线程操作等待中... //B执行的notify随机唤醒了A线程
A不该此线程操作等待中... //A线程不满足条件堵塞中,现在ABC都堵塞了,没人再去执行notify()
//进入..死循环
public class ConditionTest {
//共享变量 标志位 A = 1 B = 2 C = 3
int count = 1;
Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
public static void main(String[] args) {
ConditionTest conditionTest = new ConditionTest();
new Thread(() -> {
try {
for (int i = 0 ;i < 10 ; i++)
conditionTest.printA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "A").start();
new Thread(() -> {
try {
for (int i = 0 ;i < 10 ; i++)
conditionTest.printB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "B").start();
new Thread(() -> {
try {
for (int i = 0 ;i < 10 ; i++)
conditionTest.printC();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "C").start();
}
public void printA() throws InterruptedException {
lock.lock();
try {
while (count != 1){
System.out.println(Thread.currentThread().getName()+"不该此线程操作等待中...");
condition1.await();
}
for (int i = 1; i <6 ; i++) {
System.out.println(Thread.currentThread().getName()+"打印"+i);
}
count = 2;
condition2.signal();
} finally {
lock.unlock();
}
}
public void printB() throws InterruptedException {
lock.lock();
try {
while (count != 2){
System.out.println(Thread.currentThread().getName()+"不该此线程操作等待中...");
condition2.await();
}
for (int i = 6; i <11 ; i++) {
System.out.println(Thread.currentThread().getName()+"打印"+i);
}
count = 3;
condition3.signal();
} finally {
lock.unlock();
}
}
public void printC() throws InterruptedException {
lock.lock();
try {
while (count != 3){
System.out.println(Thread.currentThread().getName()+"不该此线程操作等待中...");
condition3.await();
}
for (int i = 11; i <16 ; i++) {
System.out.println(Thread.currentThread().getName()+"打印"+i);
}
count = 1;
condition1.signal();
} finally {
lock.unlock();
}
}
通过condition1 ,2,3 进行精确唤醒。