我有一段这样的代码:
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,一般不会出现数字结果无法预知的
问题,而上面的问题关键是这种写法会在多线程同时访问中会出问题。
分享到:
相关推荐
本文将详细讲解如何使用Java中的LinkedList类来模拟这两种数据结构,并实现其基本操作。 堆栈(Stack)是一种后进先出(LIFO, Last In First Out)的数据结构,它遵循“先进后出”的原则。常见的堆栈操作有压栈...
LinkedList不仅可以作为列表使用,还可以被巧妙地利用来构建栈(Stack)和队列(Queue)这两种基本数据结构。在本篇内容中,我们将探讨如何通过LinkedList实现栈和队列,以及它们在实际编程中的应用。 首先,栈是一...
LinkedList 是 Java 中的一种数据结构,属于线性数据结构的一种,但它与数组有着本质的不同。数组在内存中存储元素是连续的,而 LinkedList 则通过节点之间的引用相互连接,每个节点包含元素本身、指向前一个节点的...
### 关于ArrayList与LinkedList的区别 在Java编程语言中,`ArrayList`与`LinkedList`都是`List`接口的具体实现类,用于存储元素集合。虽然它们都实现了同样的接口并且提供了相同的基本功能,但在内部实现机制、性能...
在Java编程语言中,LinkedList集合类是一个非常重要的数据结构,它可以用来实现栈和队列这两种特殊的数据结构。LinkedList是一个双链表,每个节点包含数据元素和两个引用,分别指向前后节点,这使得在列表中进行插入...
本篇文章将探讨如何利用`LinkedList`来实现队列和栈这两种数据结构,以及其背后的原理和源码分析。 ### 1. 队列(Queue) 队列是一种先进先出(FIFO, First In First Out)的数据结构。在Java中,可以使用`...
ArrayList、LinkedList、Vector 是 Java 中常用的数据结构实现类,它们都实现了 List 接口,但它们在存储方式、性能、线程安全性等方面有着不同特点。 首先,ArrayList 和 Vector 都是采用数组方式存储数据的,这种...
### List-LinkedList 单链表就地反转 #### 概述 本文主要介绍单链表的就地反转算法实现,并通过具体的C语言代码示例来解释这一过程。单链表是一种常见的线性数据结构,其中每个元素包含一个指向下一个元素的指针。...
LinkedList是计算机科学中的一种基本数据结构,特别是在C++编程中,它被广泛用于处理动态集合。LinkedList的主要特点是每个元素(称为节点)包含数据以及指向下一个节点的指针,这种结构使得在列表中间添加或删除...
在提供的JiHe6.java源代码中,可能包含了关于LinkedList添加删除操作的示例实现,通过阅读和理解代码,可以进一步加深对LinkedList的理解。而Java.jpg文件可能是与这个主题相关的辅助图表或类图,帮助视觉上理解...
这个数据结构允许我们在列表的任何位置进行插入和删除操作,具有O(1)的时间复杂度,这使得LinkedList在需要频繁进行这些操作时比ArrayList更高效。LinkedList类位于java.util包中,它还实现了Deque(双端队列)接口...
在IT领域,特别是Java编程中,ArrayList和LinkedList是两种非常重要的数据结构,它们都是List接口的实现类。理解这两者的区别对于优化程序性能至关重要。面试官询问这些知识点,旨在评估应聘者的理论基础和实践能力...
1,ArrayList是数组的数据结构,LinkedList是链表的数据结构。 2,随机访问的时候,ArrayList的效率比较高,因为LinkedList要移动指针,而ArrayList是基于 3,索引(index)的数据结构,可以直接映射到。 4,插入、...
LinkedList是Java编程语言中的一种重要数据结构,它属于集合框架的一部分,主要用来存储有序的元素序列。LinkedList在实现上是一个双链表,每个节点(Node)包含数据元素和两个引用,一个指向前一个节点,另一个指向...
本文对比了 LinkedList 和 ArrayList 的查询效率,从底层数据结构和 CPU 缓存两个方面进行了分析。首先,从底层数据结构方面,ArrayList 的查询效率高于 LinkedList,因为 ArrayList 底层数据结构是动态数组,可以...
return stack.removeFirst(); } } ``` 2. 使用`java.util.concurrent`包:Java并发库提供了更高级的同步机制,如`BlockingQueue`。我们可以将LinkedList作为`BlockingQueue`的实现,利用其内置的线程安全特性。...
在Java中,`java.util.LinkedList`类是链表数据结构的一个实现,它同时实现了`List`和`Deque`接口,支持双向遍历。 这个工程包含的Java文件可能涵盖了以下链表操作和概念: 1. **初始化链表**:创建一个空的链表,...
在Java编程中,LinkedList是一个非常重要的数据结构,它实现了List接口,允许我们在列表的任何位置进行插入和删除操作。LinkedList内部使用双向链表实现,因此它的遍历速度比ArrayList快,但随机访问性能较差。本...
LinkedList是基于双向链表实现的列表,每个节点包含数据和两个引用,分别指向前后节点。LinkedList在插入和删除操作时具有优势,因为它只需要改变相邻节点的引用即可,而无需移动元素。然而,对于随机读取,...