论述题
6. 下面这段代码在一些特定的情况下有问题,请指出并改正。
import java.util.List;
import java.util.ArrayList;
public class MyStack
{
private List<String>stack=new ArrayList<String>();
public synchronized void push(String value)
{
synchronized(this)
{
stack.add(value);
notify();
}
}
public synchronized String pop() throws InterruptedException
{
synchronized(this)
{
if(stack.size()<=0)
{
wait();
}
return stack.remove(stack.size()-1);
}
}
}
【正确答案】以上这段代码在大部分情况下都能正常运行,但在下面的场景中会有问题:
在多线程访问这个栈的时候,如果有三个线程按照如下的顺序访问,问题就会暴露。
1)线程1先执行pop操作,此时,由于list的大小为0,因此,会调用wait释放等待锁。
2)线程2执行push操作,往队列里放了一个元素,这个线程会调用notify来唤醒等待的线程。
3)就在此时恰好另外一个线程3也执行pop操作,那么线程1和线程3的执行顺序是无法保证的。如果恰好线程3先执行pop操作,执行完成后,线程2被唤醒,此时线程2会执行returnstack.remove(stack.size()-1)操作,由于此时队列已经为空,stack.size()的返回值为0,所以,程序会抛出java.lang.ArrayIndexOutOfBoundsException异常。
以上问题的解决方法也很简单,即在pop操作调用remove方法前再进行一次判断,判断列表里是否还有元素,实现代码如下:
public synchronized String pop()throws IntermptedException
{
synchronized(this)
{
if(stack.size()<=0)
{
wait();
}
if(stack.size()<=0)
return null;
else
return stack.remove(stack.size()-1);
}
【答案解析】