`
22cgreen
  • 浏览: 53527 次
  • 性别: Icon_minigender_2
  • 来自: 广州
社区版块
存档分类
最新评论

关于数据LinkedList的removefirst出错

阅读更多
我有一段这样的代码:

Java codeprivate LinkedList<Connection> freeCon = new LinkedList<Connection>();
public  Connection getConn()
{
Connection re = null;
if(freeCon.size()>0)
{
try {
re = freeCon.getFirst();
freeCon.removeFirst();
if(re.isClosed())
{
this.getConn();
}
} catch (SQLException e) {
e.printStackTrace();
} catch(NoSuchElementException e)
{
System.out.println("freeCon size:"+freeCon.size());
for(int i=0;i<freeCon.size();i++)
{
if(freeCon.get(i)==null)
{
System.out.println("freeCon.get("+i+")is Null");
}else{
System.out.println("Item is:"+freeCon.get(i).toString());
}
}
}
}else{
re = this.getConnByDateSource();
}
return re;
}

此代码有时会出现java.util.NoSuchElementException
java.util.LinkedList.remove(Unknown Source)
java.util.LinkedList.removeFirst(Unknown Source)
dlp.oa.sql.SqlOracle.getConn(SqlOracle.java:117)
这个异常不常发生,一般好几天发生一次,让我感到很奇怪的就是,re = freeCon.getFirst();没有出现NoSuchElementException为什么freeCon.remov
eFirst();会发生异常呢.看那个高手能道出个原因出来.

此错误重启tomcat就好了.

---------------------------------------------------------------------------------------------------------------
在我后期打的测试代码中发现,freeCon.size()输出结果为4,但freeCon.get(0)出现异常,同时在输入结果中连续出现多个
freeCon size:4字样,而且出现这种情况是因为异步发送邮件写日志的过程中,从记录的异常分析,因为异步的原因,发送邮件的线程
在一个时间里同时调用了这个方法再出现LinkedList出错的.

在没有同步的情况下.
LinkedList 出现size=4,但实际上LinkedList中没有任何元素的现象.

按常理来说,不管同步和异步,一个数的状态最后只有一种状态,为什么会使得size大小和实际元素不对呢.
我们从LinkedList源码来分析一下为什么会出现这种现象.
看一下size怎么来的.
public int size() {
return size;
    }
   
    可以看出是返回LinkedList的一个int类型的size属性,不过从这里可以看出LinkedList最大元素个数不能超过int类型的最大允许范围.
    其实上面一个方法的关键大于freeCon.removeFirst(),
    而re = freeCon.getFirst();只是读取元素,并不会对元素个数和实际个数不同步产生影响,我们来看看freeCon.removeFirst()
    -------------------------------------------------------------------------------------------
     public E removeFirst() {
return remove(header.next);
    }
    ---------------------------------------------------------------------------------------------
     private E remove(Entry<E> e) {
if (e == header)
    throw new NoSuchElementException();

        E result = e.element;
e.previous.next = e.next;
e.next.previous = e.previous;
        e.next = e.previous = null;
        e.element = null;
size--;
modCount++;
        return result;
    }
   
    这里有个疑问就是,不管有多少个线程同时操作这个方法,这里测试过,当一个线程出现异常并不会影响其它线的中断(其它没有异常的线程一样继续执行),
    因此就算10个线程同时调用这个方法,按理size最终应减少10次啊。最少不会size=4,元素就为空了,最少减少一个元素
    我就size减一,不管先后顺序最后结果都是-10,元素应对应size大小啊,最多size等于负数。也不存在size大于元素的情况。
   
    这里看来唯一出现问题的就是这段了。
   
     E result = e.element;
e.previous.next = e.next;
e.next.previous = e.previous;
        e.next = e.previous = null;
        e.element = null;
       
        我们想一下这时有一个线程执行到第4行代码,而别一个线程刚好执行到了第二行代码,这时会出现
        e.next = null, e.previous = null,为因第4行代码的原因,使得e发现了变化,但是另一线程并不知道e发生了变化
        他还当作原来的e在使用。
       
        我们再详细的说明一下:
        E result = e.element; element是一个对象的引用,对应于对象A吧。这里就是A的引用给了result
        e.previous.next = e.next; 把e的下一个引用作为e的上一引用中的下一个引用。也就是说
        e的下一个元素是e的上一个元素的下一个素,从而可以知自己被被排除了,就像1,2,3 这时2的上一个元素1,下一个元素3,
        这时有人说1的下一个元素是3,这时我们就成了1,3,当然只是说1的下一元素为3,那么虽然不能通过1找到2,但是可以通过
        3的上元素来找到2。因此就有了下面一行语句。
        e.next.previous = e.previous; 相当于说3的上一个元互为1。这时就元素从上元素及下一个元素来得到2了。
       
        e.next = e.previous = null; 这条语句就是把对象置null,使其能被垃圾回收器回收。
       
        e.element = null; 也是把其置null,给垃圾回收器回收,其实它的引用早传给了E result
       
        多线程一般只是发生计算时不按顺序执行的问题,一般不会出现数据不对的问题,如:我多个线程对i加1,不管谁先加1,但
        可以确定最后的结果,有多少个线程加1,就加了多少次,4个线程同时操作就是+4,一般不会出现数字结果无法预知的
        问题,而上面的问题关键是这种写法会在多线程同时访问中会出问题。
1
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics