下面代码在一些特定的情况有问题,请指出并改正
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);
}
}
}
看到这道题,我也楞了好久。发现自己JAVA多线程的知识掌握得不是很牢靠。
看书后原来啊这个代码在大部分情况下都能正常运行,但在下面的场景中会有问题。
在多线程访问这个栈的时候,如果有三个线程按照如下的顺序访问,问题就会暴露
一、线程1先执行pop操作,此时,list大小为0,因此会调用wait释放等待锁
二、线程2执行push操作,往队列里放了一个元素,这个线程会调用notify来唤醒等待的线程
三、就在此时线程3恰好也执行pop操作,那么线程1和线程3的执行顺序是无法保证的。如果恰好线程3先执行pop,执行完成后线程2被唤醒,此时线程2会执行return stack.remove(stack.size()-1)操作,由于此时队列为空,stack.size()的返回值为0,所以,程序会抛出java.lang.ArrayIndexOutOfBoundsException异常
解决办法即是在pop操作调用remove方法前加一次判断,判断列表里是否还有元素
public synchronized String pop() throws InterruptedException
{
synchronized(this)
{
if(stack.size()<=0)
{
wait();
}
if(stack.size()<=0)
return null;
else
return stack.remove(stack.size()-1);
}
}
这样就解决了