《JAVA多线程编程核心技术》3.1.10的错误纠正

我看的书作者:高洪岩

书版本:2015年11月第1版第3次印刷

问题概述:

3.1.10 主要讲解 等待wait的条件发生变化的场景

为了方便起见,我就不照抄书中原码了,我用我自己的代码 就是一个main方法 我用的jdk1.6

public static void main(String[] args) throws InterruptedException {
final List<String> list = new ArrayList<String>();
final Object lock = new Object();
// 等待&删除
Runnable waitRun = new Runnable() {
@Override
public void run() {
synchronized( lock ){
try {
if( list.size() == 0 ){
System.out.println("wait begin t="+Thread.currentThread().getName());
lock.wait();
System.out.println("wait end"+Thread.currentThread().getName());
}
System.out.println("list remove begin"+Thread.currentThread().getName());
list.remove( 0 );
System.out.println("list remove end "+Thread.currentThread().getName() + " size="+list.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
// 唤醒&增加
Runnable notifyRun = new Runnable() {
@Override
public void run() {
synchronized( lock ){
System.out.println("list add");
list.add( "1" );
System.out.println("notify begin");
lock.notifyAll();
System.out.println("notify end");
}
}
};
//线程1-删除操作 锁等待
Thread waitT1 = new Thread( waitRun );
waitT1.start();
//线程2-删除操作 锁等待
Thread waitT2 = new Thread( waitRun );
waitT2.start();
Thread.sleep( 1000L );
//线程3-增加操作 唤醒所有等待
Thread notifyT1 = new Thread( notifyRun );
notifyT1.start();
}

这样有个问题就如书中据说 会有一个删除操作 异常 因为已无元素可删。

[color=red][b]Exception in thread "Thread-0" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0[/b][/color]

书中给出的解决方案是这样的

是在删除线程中 while(list.size==0) 这样可以保证在有元素的时候执行删除操作。

//        等待&删除
Runnable waitRun = new Runnable() {
@Override
public void run() {
synchronized( lock ){
try {
// 此处是修改点 由原来的if 改成 while
while( list.size() == 0 ){
System.out.println("wait begin t="+Thread.currentThread().getName());
lock.wait();
System.out.println("wait end"+Thread.currentThread().getName());
}
System.out.println("list remove begin"+Thread.currentThread().getName());
list.remove( 0 );
System.out.println("list remove end "+Thread.currentThread().getName() + " size="+list.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};

这样确实保证了有元素时才删除,因为当你无元素时,会一直循环wait()操作。

但这有个问题是第二个删除线程 因为集合已无元素删除了,会多一个wait,而这个wait()是在notifyAll之产生的,会永远唤醒不了。

所以这个做法属于解决了旧问题,又产生新的问题。

而我的做法是这样的

Runnable waitRun = new Runnable() {
@Override
public void run() {
synchronized( lock ){
try {
System.out.println("wait begin t="+Thread.currentThread().getName());
lock.wait();
System.out.println("wait end"+Thread.currentThread().getName());
// 是否执行过删除
boolean deleteFlag = false;
System.out.println( "list size="+list.size() +" remove before");
while( list.size() > 0 && deleteFlag == false ){
System.out.println("list remove begin"+Thread.currentThread().getName());
list.remove( 0 );
System.out.println("list remove end "+Thread.currentThread().getName() + " size="+list.size());
deleteFlag = true;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};

思路是这样的,不能在wait()动手脚,转移到删除元素上,循环list.size >0 && 没有执行过操作 才执行删除并且只能执行一次 这样就解决了这个问题了。

[size=large][b]总结[/b][/size]:

遇到wait条件变化时,基本思路就是用while的方法让线程一直处于等待,待条件满足时才执行下一步。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值