From 9d1e8205a2d362a33e142a49db1787fe5145ce3f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 5 Jun 2015 08:46:06 +0200 Subject: made i/o and memory intensive operations execute in serial order --- .../services/XmppConnectionService.java | 29 +++++++++++------- .../utils/SerialSingleThreadExecutor.java | 34 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/utils/SerialSingleThreadExecutor.java diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 7b5532a4..0a264dd1 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -77,6 +77,7 @@ import eu.siacs.conversations.utils.ExceptionHelper; import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener; import eu.siacs.conversations.utils.PRNGFixes; import eu.siacs.conversations.utils.PhoneHelper; +import eu.siacs.conversations.utils.SerialSingleThreadExecutor; import eu.siacs.conversations.utils.Xmlns; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnBindListener; @@ -119,6 +120,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa startService(intent); } }; + + private final SerialSingleThreadExecutor mFileAddingExecutor = new SerialSingleThreadExecutor(); + private final SerialSingleThreadExecutor mDatabaseExecutor = new SerialSingleThreadExecutor(); + private final IBinder mBinder = new XmppConnectionBinder(); private final List conversations = new CopyOnWriteArrayList<>(); private final FileObserver fileObserver = new FileObserver( @@ -373,7 +378,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa callback.success(message); } } else { - new Thread(new Runnable() { + mFileAddingExecutor.execute(new Runnable() { @Override public void run() { try { @@ -388,8 +393,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa callback.error(e.getResId(),message); } } - }).start(); - + }); } } @@ -405,7 +409,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } message.setCounterpart(conversation.getNextCounterpart()); message.setType(Message.TYPE_IMAGE); - new Thread(new Runnable() { + mFileAddingExecutor.execute(new Runnable() { @Override public void run() { @@ -420,7 +424,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa callback.error(e.getResId(), message); } } - }).start(); + }); } public Conversation find(Bookmark bookmark) { @@ -976,7 +980,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa Account account = accountLookupTable.get(conversation.getAccountUuid()); conversation.setAccount(account); } - new Thread(new Runnable() { + Runnable runnable =new Runnable() { @Override public void run() { Log.d(Config.LOGTAG,"restoring roster"); @@ -997,7 +1001,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa Log.d(Config.LOGTAG,"restored all messages"); updateConversationUi(); } - }).start(); + }; + mDatabaseExecutor.execute(runnable); } } @@ -1066,7 +1071,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa if (XmppConnectionService.this.getMessageArchiveService().queryInProgress(conversation,callback)) { return; } - new Thread(new Runnable() { + Runnable runnable = new Runnable() { @Override public void run() { final Account account = conversation.getAccount(); @@ -1085,7 +1090,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa callback.informUser(R.string.fetching_history_from_server); } } - }).start(); + }; + mDatabaseExecutor.execute(runnable); } public List getAccounts() { @@ -2344,13 +2350,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public void syncRosterToDisk(final Account account) { - new Thread(new Runnable() { + Runnable runnable = new Runnable() { @Override public void run() { databaseBackend.writeRoster(account.getRoster()); } - }).start(); + }; + mDatabaseExecutor.execute(runnable); } diff --git a/src/main/java/eu/siacs/conversations/utils/SerialSingleThreadExecutor.java b/src/main/java/eu/siacs/conversations/utils/SerialSingleThreadExecutor.java new file mode 100644 index 00000000..bfb4668d --- /dev/null +++ b/src/main/java/eu/siacs/conversations/utils/SerialSingleThreadExecutor.java @@ -0,0 +1,34 @@ +package eu.siacs.conversations.utils; + +import java.util.ArrayDeque; +import java.util.Queue; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +public class SerialSingleThreadExecutor implements Executor { + + final Executor executor = Executors.newSingleThreadExecutor(); + final Queue tasks = new ArrayDeque(); + Runnable active; + + public synchronized void execute(final Runnable r) { + tasks.offer(new Runnable() { + public void run() { + try { + r.run(); + } finally { + scheduleNext(); + } + } + }); + if (active == null) { + scheduleNext(); + } + } + + protected synchronized void scheduleNext() { + if ((active = tasks.poll()) != null) { + executor.execute(active); + } + } +} \ No newline at end of file -- cgit v1.2.3