I have implemented a thread in an Android app that is invoked every minute, the invocation of the process occur through an Alarm Manager.
@Override public void onReceive(Context context, Intent intent) { try { PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wakeLock; if (powerManager != null) { wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Send-data"); wakeLock.acquire(10 * 60 * 1000L); new Thread(new SendPolicyData(context)).start(); wakeLock.release(); } } catch (Exception e) { wil.WriteFile("1)AlarmSendData - Exception: " + e.toString()); } }
The code contained in the thread extract a set of data from a database that must be sent through posts to a server, the access to resources is controlled via a semaphore.
@SuppressWarnings("ResultOfMethodCallIgnored") public class SendPolicyData implements Runnable { private static final WriteInLogFile wil = new WriteInLogFile(); private final Context ctx; public SendPolicyData(Context ctx) { this.ctx = ctx; } public void run() { try { SemaphoreDTS.getInstance().goIn(); Authentication singleCall = new Authentication(); Utilities utilities = new Utilities(ctx); DbGest dbGest = DbGest.getInstance(ctx); if (utilities.checkConnection()) { int lastProcessedID = -1; int attempts = 0; Cursor cursor = dbGest.freeQuery("SELECT id, label, value, priority FROM " + TABLE_DATATOSEND + " ORDER BY priority,dateIns"); if (cursor != null) { cursor.moveToFirst(); if (cursor.getCount() > 0) { do { int toProcessID = cursor.getInt(cursor.getColumnIndex("id")); String value = cursor.getString(cursor.getColumnIndex("value")); String labelString = cursor.getString(cursor.getColumnIndex("label")); if (lastProcessedID == toProcessID) { if (attempts <= 5) { attempts++; Thread.sleep(3000); } else { attempts = 0; dbGest.changeDTSRecordPriority(toProcessID); } } switch (labelString) { case "photo": //DO STUFF break; lastProcessedID = toProcessID; } while (cursor.moveToNext()); } cursor.close(); } } } catch (Exception e) { SemaphoreDTS.getInstance().goOut(); wil.WriteFile("7)SendPolicyData - Exception: " + e.toString()); } finally { SemaphoreDTS.getInstance().goOut(); } SemaphoreDTS.getInstance().goOut(); }
}
This is the source code of the semaphore that I use to manage the access to the resources.
public class SemaphoreDTS { private static SemaphoreDTS instance; private final Semaphore semaphore; private final WriteInLogFile wil = new WriteInLogFile(); private SemaphoreDTS() { this.semaphore = new Semaphore(1, true); } public static SemaphoreDTS getInstance() { if (instance == null) { instance = new SemaphoreDTS(); } return instance; } public synchronized void goIn() { try { semaphore.acquire(); } catch (Exception e) { wil.WriteFile("1)SemaphoreDTS - Exception: " + e.toString()); } } public synchronized void goOut() { try { semaphore.release(); } catch (Exception e) { wil.WriteFile("2)SemaphoreDTS - Exception: " + e.toString()); } } }
During the tests that I did, it often happens that the semaphore remains blocked, for some reason the necessary release is not invoked in order to be able to perform new acquire.
I think I have written the code correctly and I don’t understand where I am wrong.
Advertisement
Answer
In this code’s block:
catch (Exception e) { SemaphoreDTS.getInstance().goOut(); wil.WriteFile("7)SendPolicyData - Exception: " + e.toString()); } finally { SemaphoreDTS.getInstance().goOut(); } SemaphoreDTS.getInstance().goOut();
You always have two calls .goOut()
, because finally
block always will invoke.
When you call .release() (in your method .goOut()
) semaphore gets availible permit, i.e instead 1 permit your semaphore gets 2 permits. I think problem starts here. Try to delete calls `.goOut() method everywhere but not in finally()