最新一直工作比较忙,一直木有空继续写这个数据库。
今天主要解决的是数据读写移除的冲突问题。
数据库设计的时候是按照内存数据库来构思的,所以所有的数据实际上都是保存在ArrayList中的。
因此会出现如下的问题:
-----------------------------------------
线程1正在循环读取数据
for(DataCell:dataList) {
//TODO
}
此时线程2又对数据进行了删除操作
dataList.remove(1)
-----------------------------------------
这个时候,JAVA就会报java.util.ConcurrentModificationException。
针对上述情况,我们一般可能想到的对应方法是使用synchronized。
synchronized(dataList) {
for(DataCell:dataList) {
//TODO
}
}
synchronized(dataList) {
dataList.remove(1)
}
这样的写法的确可以通过同步来控制,但是如果我有3个线程,其中2个线程
只是循环读取数据, 如果使用如上写法,就会造成1个线程读取完毕,另外一个线程继续读取的现象。
会影响读取的效率。
回过头来仔细想一下,其实我们只是希望将add/remove和循环read的操作进行乎斥即可。
即循环read的时候不能对dataList进行操作。而删除的时候也不能进行循环读写。
按照上述的思想,我们可以有2个方法(不是很完美,但是能解决这个问题)
方法1.规定只用使用foreach语法来循环调用这个数组。且不能中途推出循环
这样,我们就可以复写iretor,将hastnext认为是循环开始的触发函数,netx()为null的时候认为是循环结束的条件。
但是这样的规定比较固定,所以可能导致程序编写有很多限制.暂时没有使用这个方法.
示例代码如下:
class DataCellList extends ArrayList<Integer>{
boolean isCanRemove = false;
class myIteratorDector implements Iterator<Integer>{
public Iterator dectorIre;
public myIteratorDector(Iterator ite) {
dectorIre = ite;
}
@Override
public boolean hasNext() {
System.out.println("iterator hasnext");
return dectorIre.hasNext();
}
@Override
public Integer next() {
System.out.println("iterator next");
Integer nextV = (Integer) dectorIre.next();
return nextV;
}
@Override
public void remove() {
dectorIre.remove();
}
}
/**
*
*/
private static final long serialVersionUID = 1L;
public Iterator<Integer>iterator() {
System.out.println("iterator");
return new myIteratorDector(super.iterator());
}
}
方法2:增加2个接口来表示进入循环和退出循环,进入循环的时候,判断当前是否有remove的操作,如果有,就开始等待. 如果remove操作结束.接口继续作如下处理:循环计数器+1 循环结束的时候,调用退出循环接口,则循环计数器-1,然后确认是否有remove操作应为这个循环而在wait,如果有则激活remove处理.
相关代码:
public class DataCellList extends ArrayList<DataCell>{
private int currentInLoop = 0;
private int currentInRemoving = 0;
private Object mWaitForLoopObj = new Object();
private Object mWaitForRemoveAddObj = new Object();
public void enterLooper() {
//DebugThread debugThread = new DebugThread();
//debugThread.start();
if(currentInRemoving != 0) {
try {
synchronized(mWaitForRemoveAddObj) {
mWaitForRemoveAddObj.wait();
}
} catch (InterruptedException e) {
LogUtil.e(TAG, "setRemovingFlag error" + e.toString());
}
}
currentInLoop++;
}
public void leaveLooper() {
currentInLoop--;
if(currentInLoop == 0) {
synchronized(mWaitForLoopObj) {
mWaitForLoopObj.notify();
}
}
}
public boolean add(DataCell data) {
data.setId(this.size());
setRemoveAddFlag();
boolean result = super.add(data);
clearRemoveAddFlag();
return result;
}
public DataCell remove(int index) {
//this method is fobbiden
setRemoveAddFlag();
DataCell result = super.remove(index);
clearRemoveAddFlag();
return result;
}
private void setRemoveAddFlag() {
if(currentInLoop != 0) {
try {
synchronized(mWaitForLoopObj) {
mWaitForLoopObj.wait();
}
} catch (InterruptedException e) {
LogUtil.e(TAG, "setRemovingFlag error" + e.toString());
}
}
currentInRemoving++;
}
private void clearRemoveAddFlag() {
currentInRemoving--;
if(currentInRemoving == 0) {
synchronized(mWaitForRemoveAddObj) {
mWaitForRemoveAddObj.notify();
}
}
}
}