虚假唤醒
public class Tick {
public static void main(String[] args) {
Data date = new Data();
//建立4个线程,两个加,两个减
new Thread(()->{
try {
for (int i=0;i<20;i++)
date.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
date.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
try {
for (int i=0;i<20;i++)
date.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
date.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
class Data{
private int number=0;
public synchronized void increment() throws InterruptedException {
if (number!=0) //如果还有就等待
this.wait();
number++;
System.out.println(Thread.currentThread().getName()+" incr->"+number);
this.notify();
}
public synchronized void decrement()throws InterruptedException{
if (number==0) //如果没有了就等待
this.wait();
number--;
System.out.println(Thread.currentThread().getName()+" decr->"+number);
this.notify();
}
}
复制代码
运行结果:
。。。。。。省略上下文
C incr->1
A incr->2
C incr->3
。。。。。。
复制代码
原因:
- 当我们在if中使用wait()时,如果保持着++,–的次序则不会出错。
- 如果当线程A等待时,如果线程C获取了锁进行++操作后释放锁,A获得锁。然后A直接走wait之后的代码不进行条件判断,因而出错。
解决:
使用while 而不是 if 如
public synchronized void decrement()throws InterruptedException{
while (number==0) //如果没有了就等待
this.wait();
number--;
System.out.println(Thread.currentThread().getName()+" decr->"+number);
this.notify();
}
复制代码
精准唤醒 single
官方文档single的实施注意:
当调用此方法时,实现可能(通常是)要求当前线程保存与此Condition的锁
执行必须记录此前提条件,如果不保持锁定,则采取任何措施。
通常情况下,一个异常如IllegalMonitorStateException将被抛出。
复制代码
- 定义多个condition,创建多个等待队列
- 通过condition.single唤醒等待队列中等待最久的线程,由于多个等待队列中都只有一个线程在等待因此可以精准唤醒
public class TestCondistion {
public static void main(String[] args) {
Data3 date = new Data3();
// 设置ABCD四个线程,分别调用printA,B,C,D
new Thread(()->{
try {
for (int i=0;i<20;i++)
date.printA();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
//省略相似代码
}
}
class Data3{
private int number=0;
private Lock lock=new ReentrantLock();
//创建多个condition
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private Condition condition4 = lock.newCondition();
public void printA() throws InterruptedException {
lock.lock();
try{
while (number!=0)
condition1.await();
number++;
System.out.println(Thread.currentThread().getName()+" incr->"+number);
//唤醒condition2等待队列中等待最久的那个一个,由于只有printB在condition2的等待队列中所以可以精准唤醒printB
condition2.signal();
}catch (Exception exception){
System.err.println("incr wrong");;
}finally {
lock.unlock();
}
}
public void printB()throws InterruptedException{
lock.lock();
try {
while ( number==0)
condition2.await();
number--;
System.out.println(Thread.currentThread().getName()+" decr->"+number);
condition3.signal();
}catch (Exception ex){
System.err.println("decr wrong");
}finally {
lock.unlock();
}
}
public void printC()throws InterruptedException{
lock.lock();
try {
while ( number!=0)
condition3.await();
number++;
System.out.println(Thread.currentThread().getName()+" incr->"+number);
condition4.signal();
}catch (Exception ex){
System.err.println("incr wrong");
}finally {
lock.unlock();
}
}
public void printD()throws InterruptedException{
lock.lock();
try {
while ( number==0)
condition4.await();
number--;
System.out.println(Thread.currentThread().getName()+" decr->"+number);
condition1.signal();
}catch (Exception ex){
System.err.println("decr wrong");
}finally {
lock.unlock();
}
}
}
复制代码
运行结果:
A incr->1
B decr->0
C incr->1
D decr->0
A incr->1
B decr->0
C incr->1
D decr->0
A incr->1
B decr->0
C incr->1
D decr->0
A incr->1
B decr->0
C incr->1
D decr->0
A incr->1
B decr->0
C incr->1
D decr->0
A incr->1
B decr->0
C incr->1
D decr->0
A incr->1
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END