package com.java.thread.lifecycle;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
@author Administrator
*
*/
public class OneTaskTwoThread {
static char currentThread = 'A';
static Object object = new Object();
public static void main(String[] args) {
List list = getList();
Thread threadA = new Thread(new Task(object, list, currentThread), "Thread-a");
Thread threadB = new Thread(new Task(object, list, currentThread), "Thread-b");
threadA.start();
threadB.start();
}
private static List getList() {
List list = new ArrayList();
for (int i = 0; i < 20; i++) {
list.add(Integer.toString(i));
}
return list;
}
}
class Task implements Runnable {
static List list;
static char currentThread;
Object object;
public Task(Object object, List<String> list, char currentThread) {
Task.list = list;
Task.currentThread = currentThread;
this.object = object;
}
@Override
public void run() {
synchronized (object) {
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
// 打印ModCount
// printModCount("remove before" + " curent size" + list.size(), iterator,
// list);
try {
if (Thread.currentThread().getName().equals("Thread-a") && currentThread != 'A') {
object.wait();
} else if (Thread.currentThread().getName().equals("Thread-b") && currentThread != 'B') {
object.wait();
} else {
String str = iterator.next();
iterator.remove();
// 打印ModCount
// printModCount("remove after", iterator, list);
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + ": remove \"" + str
+ "\" and current size : " + list.size());
if (Thread.currentThread().getName().equals("Thread-a")) {
Task.currentThread = 'B';
}
if (Thread.currentThread().getName().equals("Thread-b")) {
Task.currentThread = 'A';
}
object.notifyAll();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
private void printModCount(String prefix, Iterator<String> iterator, List<String> list2) {
System.out.println(prefix + " : " + iterator + " iterator expectedModCount : "
+ ReflectUtil.findDeclaredFieldValueByName(iterator, "expectedModCount") + " ,list modCount : "
+ ReflectUtil.findDeclaredFieldValueByName(list, "modCount"));
}
}
class ReflectUtil {
/**
*
* @Description
* @date 2018年5月7日
* @author Administrator
* @return
* @Throws
*/
public static Field[] findAllDeclaredFields(Object obj) {
Class<? extends Object> clazz = obj.getClass();
Field[] fields = new Field[0];
fields = findDeclaredFields(clazz, fields);
return fields;
}
private static Field[] findDeclaredFields(Class<? extends Object> clazz, Field[] fields) {
// 查找当前类中的属性
Field[] tempFields = clazz.getDeclaredFields();
// 合并tempFields到fields
int oldLen = fields.length;
// Arrays.copyOf产生了新的fields数组,最后要return出去
fields = Arrays.copyOf(fields, oldLen + tempFields.length);
System.arraycopy(tempFields, 0, fields, oldLen, tempFields.length);
Class<? extends Object> superClazz = clazz.getSuperclass();
if (null != superClazz && !(superClazz == Object.class)) {
// fields 是通过数组扩容产生的,每次扩容都是新的要重新赋值
fields = findDeclaredFields(superClazz, fields);
}
// fields数组,return出去
return fields;
}
public static Field findDeclaredFieldByName(Object obj, String name) {
Field[] fields = ReflectUtil.findAllDeclaredFields(obj);
Field field = null;
for (int i = 0; i < fields.length; i++) {
try {
field = fields[i];
if (field.getName().equals(name)) {
field.setAccessible(true);
break;
}
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return field;
}
public static Object findDeclaredFieldValueByName(Object obj, String name) {
Field field = ReflectUtil.findDeclaredFieldByName(obj, name);
Object retObj = null;
try {
retObj = field.get(obj);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return retObj;
}
}
因为ArrayList是线程不安全的。
因此如果在使用迭代器的过程中有其他线程修改了ArrayList,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。这一策略在源码中的实现是通过 modCount 域,modCount 顾名思义就是修改次数,对ArrayList 内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的 expectedModCount。在迭代过程中,判断 modCount 跟 expectedModCount 是否相等,如果不相等就表示已经有其他线程修改了 Map:注意到 modCount 声明为 volatile,保证线程之间修改的可见性。
因为ArrayList是线程不安全的。
因此如果在使用迭代器的过程中有其他线程修改了ArrayList,那么将抛出ConcurrentModificationException,这就是所谓fail-fast策略。这一策略在源码中的实现是通过 modCount 域,modCount 顾名思义就是修改次数,对ArrayList 内容的修改都将增加这个值,那么在迭代器初始化过程中会将这个值赋给迭代器的 expectedModCount。在迭代过程中,判断 modCount 跟 expectedModCount 是否相等,如果不相等就表示已经有其他线程修改了 ArrayList:注意到 modCount 声明为 volatile,保证线程之间修改的可见性。
集合一般都会实现自己的迭代器,ArrayList->private class ListItr extends Itr implements ListIterator
其remove 方法在 Itr实现
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
调用了 ArrayList.remove,ArrayList很多方法都只改变modCount
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
再看迭代器ArrayList.Itr其中的一个循环
使用迭代器是,同步了一下 expectedModCount = modCount
迭代的时候一直在判断,如果此时调用了 ArrayList.remove,modCount变化了,expectedModCount还是初始同步的值,也就
throw new ConcurrentModificationException();
private class Itr implements Iterator<E> {
int expectedModCount = modCount; // 迭代器生成的时候赋值
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
可以看得调用它们之前和之后都会做判断,通过了才整个返回集合
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
如果迭代器遍历
@Test
public void g1111() {
ArrayList<String> al = new ArrayList<String>();
al.add("1");
al.add("2");
al.add("3");
al.add("4"); // 程序运行到这
/*
* ArrayList.iterator
* public Iterator<E> iterator() {
return new Itr(); // 在这打断点,然后f5一步步进去
}
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount; // 你会发现只有获得迭代器时同步一次
*/
for (String string : al) {
System.out.println(string);
}
}