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()