Synchronizing log entry posting to server
I have a little problem with my project. I'm developing an application for Android and a want to post my logs to a server. Almost everything works fine, but I got a little problem. I have an ArrayList in my class which handles the posts:
private ArrayList<String> logsT开发者_开发问答oPost = new ArrayList<String>();
and a method which puts data to this list and a separate thread which runs every 20 seconds and uploads the logs and empties the list after that. The problem is that I get a ConcurrentModificationException if I'm trying to write to this list while the thread tries to upload the data and clean the list. My code looks like this:
Iterator<String> keyIter = logsToPost.iterator();
while (keyIter.hasNext()) {
String next = keyIter.next();
String[] params = next.split(FormFactory.FUNCTION_SEP);
HttpData hd = HttpRequest.post(LOGCAT_LOG_URL, "userId=" + sb.userId + "&pdaId=" + sb.pdaId
+ "&tag=" + params[0] + "&logContent=" + params[1]);
logsToPost.remove(next);
}
I know that there is a synchronizedList, and synchronized blocks but I can't get synchronizedList to work on my droid. Do you have any ideas how can I implement this logging procedure? I tried using the volatile keyword but I still get the exception.
From a Java perspective:
Your code should always result in an exception since you are modifying the ArrayList using the ArrayList.remove instead of Iterator.remove while also iterating over it.
Making this change should fix your problem most of the time:
Iterator<String> keyIter = logsToPost.iterator();
while (keyIter.hasNext()) {
String next = keyIter.next();
//do something
keyIter.remove();
}
To further harden your task from the risk of failure, you should consider atomically swapping the instance of the ArrayList at the start of your logging task. So the work flow would be:
ArrayList<String> logsToPost = logListReference.getAndSet(new ArrayList<String>());
for (String logEntry:logsToPost) {
//doSomething
}
Would it be a solution to have exchange the lists when the sending process starts. So that the sending process always use the "old" list, and the writing process the "new" list.
Then you need only to synchronize writing to the new list, and exchanging them,
Let me illustrate it:
public class ListHolder {
private List newList = new List();
public syncronized List exchangeAndGetOld() {
List oldList = this.newList;
this.newList = new List();
return oldList();
}
public syncronized addToNewList(Object item) {
newList.add(item);
}
}
Use synchronized collection for the shared list:
private Vector logsToPost = new Vector();
Get the copy of that collection before you upload data:
ArrayList<String> logsToUpload; synchronized(logsToPost) { logsToUpload = new ArrayList<String>(logsToPost); logsToPost.clear(); }
Use the copy of the collection in your sending loop:
Iterator keyIter = logsToUpload.iterator();
精彩评论