3.4wait的条件发生变化导致逻辑错误

来源:互联网 发布:子曰由诲女知之乎翻译 编辑:程序博客网 时间:2024/06/07 01:50

若wait的条件需要发生变化是,需要注意程序逻辑的变化

下面有个错误例子

package com.myObject;public class AddObject {    private String lock;    public AddObject(String lock) {        this.lock = lock;    }    public void add() {        synchronized (lock) {            ValueObject.list.add("anyStr");            lock.notifyAll();        }    }}
package com.myObject;public class SubObject {    private String lock;    public SubObject(String lock) {        this.lock = lock;    }    public void sub(){        synchronized(lock){            try {                if(ValueObject.list.size()==0){//注意wait条件的变化                    System.out.println(Thread.currentThread().getName()+" wait begin " + System.currentTimeMillis());                    lock.wait();                    System.out.println(Thread.currentThread().getName()+" wait end " + System.currentTimeMillis());                }                ValueObject.list.remove(0);                System.out.println("list size "+ValueObject.list.size());            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}
package com.myObject;import java.util.ArrayList;import java.util.List;public class ValueObject {public static List list= new ArrayList();}
package com.myThread;import com.myObject.AddObject;public class Thread1a extends Thread {    AddObject addObject;    public Thread1a(AddObject addObject) {        this.addObject = addObject;    }    @Override    public void run() {        addObject.add();    }}
package com.myThread;import com.myObject.SubObject;public class Thread1b extends Thread {    SubObject subObject;    public Thread1b(SubObject subObject) {        this.subObject = subObject;    }    @Override    public void run() {        subObject.sub();    }}
package com.test;import com.myObject.AddObject;import com.myObject.SubObject;import com.myThread.Thread1a;import com.myThread.Thread1b;public class Test1 {    public static void main(String[] args) throws InterruptedException{        String lock = new String("hello");        AddObject addObject = new AddObject(lock);        SubObject subObject = new SubObject(lock);        Thread1a thread1a = new Thread1a(addObject);        thread1a.setName("add");        Thread1b thread1b1 = new Thread1b(subObject);        Thread1b thread1b2 = new Thread1b(subObject);        thread1b1.setName("sub1");        thread1b2.setName("sub2");        thread1b1.start();        thread1b2.start();        Thread.sleep(2000);        thread1a.start();    }}

打印结果

sub2 wait begin 1453104941268
sub1 wait begin 1453104941268
sub1 wait end 1453104943268
Exception in thread "sub2" list size 0
sub2 wait end 1453104943269
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.remove(ArrayList.java:387)
at com.myObject.SubObject.sub(SubObject.java:18)
at com.myThread.Thread1b.run(Thread1b.java:14)

结果分析:当sub1和sub2分别在wait之前,进行了一次判断,那时的条件都是“ValueObject.list.size()==0”,但被唤醒之后并没有再次进行判断,就继续往下执行了,然后判断的条件已经发生改变了,所以导致List的索引溢出

解决方法:这里的解决方法时使用while,把if改为while

打印结果

sub2 wait begin 1453106550825
sub1 wait begin 1453106550825
sub1 wait end 1453106552825
list size 0
sub2 wait end 1453106552826
sub2 wait begin 1453106552826

结果分析:sub1和sub2都被唤醒,sub1抢先得到资源然后使得“ValueObject.list.size()==1”退出循环,sub2紧接着得到资源,但sub2得到资源时sub1已经把ValueObject.list.size()变为0了,所以sub2继续循环然后又进入wait

0 0
原创粉丝点击