不要以为只有多线程才有并发访问问题,其实单线程也有。举个例子,对于集合,相信大家经常碰到下面这种异常:
- java.util.ConcurrentModificationException
-
atjava.util.AbstractList$Itr.checkForComodification(AbstractList.java:449)
-
atjava.util.AbstractList$Itr.next(AbstractList.java:420)
这个异常是由于并发修改集合元素引起的,大家第一个反应多半是多线程问题,结果可能怎么也找不出问题。这里我就模拟一下单线程引发这个并发问题的例子。
-
ArrayList<String>list=newArrayList<String>();
-
list.add("1");
-
list.add("2");
-
list.add("3");
-
list.add("4");
-
list.add("6");
-
for(Stringm:list){
- System.out.println(m);
-
list.add("7");
- }
上面这个例子只要一执行就会出现异常。为什么呢?
Iterator模式是用于遍历集合类的标准访问方法,我们来看看集合AbstracyList如何创建Iterator。首先AbstractList定义了一个内部类(inner class):
-
privateclassItrimplementsIterator{
- ...
- }
而iterator()方法的定义是:
-
publicIteratoriterator(){
-
returnnewItr();
- }
因此客户端不知道它通过Iterator it = a.iterator();所获得的Iterator的真正类型。
现在我们关心的是这个申明为private的Itr类是如何实现遍历AbstractList的:
-
privateclassItrimplementsIterator{
-
intcursor=0;
-
intlastRet=-1;
-
intexpectedModCount=modCount;
Itr类依靠3个int变量(还有一个隐含的AbstractList的引用)来实现遍历,cursor是下一次next()调用时元素的位置,第一次调用next()将返回索引为0的元素。lastRet记录上一次游标所在位置,因此它总是比cursor少1。
变量cursor和集合的元素个数决定hasNext():
-
publicbooleanhasNext(){
-
returncursor!=size();
- }
方法next()返回的是索引为cursor的元素,然后修改cursor和lastRet的值:
-
publicObjectnext(){
- checkForComodification();
-
try{
- Objectnext=get(cursor); //注意这里:得到下一个元素
- lastRet=cursor++;
-
returnnext;
-
}catch(IndexOutOfBoundsExceptione){
- checkForComodification();
-
thrownewNoSuchElementException();
- }
- }
expectedModCount表示期待的modCount值,用来判断在遍历过程中集合是否被修改过。AbstractList包含一个
modCount变量,它的初始值是0,当集合每被修改一次时(调用add,remove等方法),modCount加1。因此,modCount如果不
变,表示集合内容未被修改。
-
publicEget(intindex){
- rangeCheck(index); //检查范围
- checkForComodification();//注意这里:检查是否有被修改
-
returnl.get(index+offset);
- }
Itr初始化时用expectedModCount记录集合的modCount变量,此后在必要的地方它会检测modCount的值:
-
finalvoidcheckForComodification(){
-
if(modCount!=expectedModCount)
-
thrownewConcurrentModificationException();
- }
如果modCount与一开始记录在expectedModeCount中的值不等,说明集合内容被修改过,此时会抛出ConcurrentModificationException。
分享到:
相关推荐
3. **竞态条件**:如果两个或更多线程同时访问和修改同一数据,可能会导致竞态条件,从而引发错误的结果。 4. **死锁**:当两个或更多线程相互等待对方释放资源时,可能会发生死锁。设计线程间的资源获取顺序以避免...
- **同步机制**:当多个线程访问共享资源时,可能会引发数据不一致的问题。Java提供了`synchronized`关键字来实现线程同步,确保同一时刻只有一个线程执行特定代码块。 - **死锁**:如果两个或多个线程相互等待对方...
当多个线程访问同一资源时,可能会引发竞态条件(race condition),导致不可预测的行为。 - **互斥量**:`std::mutex`用于保护临界区,确保任何时候只有一个线程可以访问受保护的数据。 - **读写锁**:如果多个...
2. **多服务程序并行**:即使服务程序本身是单线程的,但若有多套服务程序同时运行,每套服务程序都有可能独立访问数据库,同样会引发并发问题。 **二、数据库并发测试方法** 1. **模拟用户并发测试**:通过测试...
在单线程程序中,所有的任务都是顺序执行的,而多线程则允许多个任务同时进行,提高了程序的并发性和执行效率。在Java、C++、Python等主流编程语言中,都提供了对多线程的支持。 **线程的创建与管理** 1. **创建...
7. **线程安全的数据结构**:某些数据结构如ConcurrentHashMap、AtomicInteger等是线程安全的,它们在设计上就考虑了多线程环境下的并发访问。 8. **死锁与竞态条件**:多线程环境下,必须预防死锁(多个线程互相...
- **同步**:为了避免多线程环境下可能出现的竞态条件,Java提供了synchronized关键字,用于控制对共享资源的访问,防止数据不一致。 - **死锁**:当两个或更多线程互相等待对方释放资源而无法继续执行时,就会...
在并发测试中,通常会创建多个线程来模拟高并发访问。 5. **收集结果与分析**: 在多线程环境中,线程间的通信和数据交换可能引发问题,因此你需要记录每个线程的执行结果,以便分析潜在的并发漏洞。 在实际测试中...
`DateFormat`类的设计允许它根据地区设置生成和解析日期字符串,但它在内部使用了一些可变状态,例如解析和格式化模式,这些状态在多个线程同时访问时可能引发问题。例如,一个线程可能正在修改模式,而另一个线程...
本文提出了一种新的并发程序模型检测方法,该方法构建了一个完整的模型,包括多线程间的交互以及单线程内部的“out of order”执行。通过使用模型检测工具,对所有可能的执行路径进行穷举检测,以发现那些传统技术...
在.NET Core并发环境下,线程安全问题是一个关键的议题,特别是在ASP.NET Core的WebAPI项目中,由于高并发请求的特性,可能导致多个线程同时访问共享资源,从而引发各种异常。文档中提到的问题主要集中在数据库上...
例如,如果多个线程同时访问共享资源,可能引发数据竞争。为解决这些问题,可以使用锁(Mutex, Semaphore)、线程同步原语(Monitor)或线程安全的数据结构(如ConcurrentQueue, ConcurrentDictionary)。 七、异常...
在单线程中,我们可以直接通过变量或参数传递数据。但在多线程环境中,由于线程间的并发执行,直接传递可能会引发数据不一致的问题。易语言提供了一种安全的方式来传递参数,即通过“线程参数”数据结构。创建线程时...
2. **线程同步**: 当多个线程访问同一资源时,可能引发竞态条件,导致数据不一致。BCB提供了几种同步机制,如TSemaphore、TMutex和TCriticalSection。例如,使用TCriticalSection可以确保同一时间只有一个线程能访问...
2. **线程同步与互斥**:在多线程环境中,数据共享可能会导致竞态条件,即多个线程同时访问和修改同一数据,可能引发错误。为此,我们需要使用锁、信号量、条件变量等机制来确保线程同步,避免数据不一致。例如,在...
- **单线程与多线程**:单线程程序只有一个执行流,而多线程则有多个执行流,可以在同一进程中并发运行。 - **线程的优势**:多线程可以提高CPU利用率,改善用户体验,如在后台下载数据的同时,用户仍能进行其他...
在单线程应用中,所有操作都按照顺序执行,而多线程则能并发执行任务,提升整体性能。 VB 6.0虽然不是设计用来处理多线程的,但它依然提供了创建和管理线程的能力,主要通过Microsoft Windows API(应用程序接口)...
在这个文件中,你可能会找到如何创建、启动、停止线程,以及如何处理线程异常、线程优先级设置、线程池使用等相关代码示例。 总之,这个"VB 多线程模块案例"将为你提供一个深入理解VB中多线程编程的平台,包括线程...
在非并发集合如`ArrayList`中,当多个线程共享集合时,如果一个线程修改了集合的状态(例如添加或删除元素),而此时其他线程正在遍历这个集合,那么后者可能会遇到不一致的数据结构,甚至抛出`...
在多线程环境下,数据共享可能会引发数据不一致的问题。Java提供了多种同步机制,如synchronized关键字、volatile变量、Lock接口(ReentrantLock、ReadWriteLock等)和Semaphore信号量。synchronized提供互斥访问,...