I need to make a thread with 2 locks.
The code worked well when using a looper thread, but I'm instead using a thread because of the simplicity of the task.
public synchronized void setY(
int value
) {
if (value != 0) {
this.value = value;
yProvided = true;
} else {
YIsZero = true;
}
notifyAll();
}
public synchronized void provideEntity(EntityInterface entity) {
if (entity != null) {
this.entity = entity;
} else {
entityIsNull = true;
}
entityProvided = true;
notifyAll();
}
private synchronized void compare(
ComparatorSemaphore.ComparatorResult result
) {
Log.d(TAG, "compare: ");
while (!entityProvided) {
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
while (!yProvided) {
try {
wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
if (!entityIsNull) {
if (YIsZero) {
result.integerIsZero(entity);
} else {
if (value != entity.getContent()) {
result.onDifferent(entity, value);
} else {
result.onEqual(entity, value);
}
}
} else {
result.dataNotFound(value);
}
YIsZero = false;
value = 0;
yProvided = false;
}
I've tried placing both locks in a single wait() but this way has shown to be the safest so far.
Both Methods are called asynchronously, both as response from 2 different SQL queries.
the LOGS
the code with LOGS
while (!entityProvided) {
Log.d(TAG, "compare: yProvided is: " + yProvided);
Log.d(TAG, "compare: entityProvided is: " + entityProvided);
try {
Log.println(Log.ASSERT, TAG, "compare: WAITING... FOR NEW ENTITY");
wait();
Log.println(Log.ASSERT, TAG, "compare: WAITING ENDS!!, entity provided");
Log.d(TAG, "compare: yProvided is: " + yProvided);
Log.d(TAG, "compare: entityProvided is: " + entityProvided);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
while (!yProvided) {
Log.d(TAG, "compare: yProvided is: " + yProvided);
Log.d(TAG, "compare: entityProvided is: " + entityProvided);
try {
Log.println(Log.ASSERT, TAG, "compare: WAITING... FOR NEW QUANTITY ");
wait();
Log.println(Log.ASSERT, TAG, "compare: WAITING ENDS!!, new quantity provided");
Log.d(TAG, "compare: yProvided is: " + yProvided);
Log.d(TAG, "compare: entityProvided is: " + entityProvided);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
Basically the notifyAll() is awaking the thread, and the while() loop is forcing it to the start of the lock, because it still locked...
there are other configurations like (!yProvided && !entityProvided) which worked from time to time so its useless, also others like ((!yProvided && !entityProvided)) or ((!yProvided) && (!entityProvided)), if you ask me why Im shotgun debugging is because I'm an ignorant.
In the worst cases, the data obtained (EntityInterface entity, I know thats a bad name, Ill change it) bypasses all the null checks for some reason.
The code still needs cleanup, I'm implementing an interface in all my entities for generalization, but I just learned about generic types and I'm gonna replaced a lot in this code, but Im sure that that has nothing to do with the behavior of the locks.
The logs behave differently on reset/reinstall, and they behave absolutely properly when placing logs in the queries observers????? what is this some kind of collapse of the wave function or some thing LMAO.
Here is the reworked Code, it works fine.
class CouplerRunnable<X, Y> implements Runnable {
private X x;
private Y y;
private volatile boolean yProvided = false;
private volatile boolean yIsNull = false;
private volatile boolean entityProvided = false;
private volatile boolean xIsNull = false;
public CouplerRunnable(JointResult<X, Y> result) {
mResult = result;
}
public synchronized void provideY(
Y y
) {
if (y != null) {
this.y = y;
} else {
yIsNull = true;
}
yProvided = true;
notifyAll();
}
public synchronized void provideX(X x) {
if (x != null) {
this.x = x;
} else {
xIsNull = true;
}
entityProvided = true;
notifyAll();
}
private synchronized void compare(
JointResult<X, Y> result
) {
Log.d(TAG, "compare: ");
while (!yProvided || !entityProvided) {
try {
Log.println(Log.ASSERT, TAG, "compare: WAITING... FOR NEW QUANTITY ");
wait();
Log.println(Log.ASSERT, TAG, "compare: WAITING ENDS!!, new quantity provided");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
result.onJointResponse(x, y);
}
yIsNull = false;
x = null;
y = null;
yProvided = false;
entityProvided = false;
xIsNull = false;
}
private JointResult<X, Y> mResult;
public interface JointResult<X, Y> {
void onJointResponse(X x, Y y);
}
public void run() {
Log.d(TAG, "run: ");
compare(
mResult
);
}
}
Some variables where kept there just in case like private volatile boolean xIsNull = false;
or private volatile boolean yIsNull = false;
but they are not being used at the moment.
The code has worked as intended,,,... maybe some lines are redundant like the nulls at the end or assigning the field variable booleans a false value...
The interface may be better to write as an @Functionalinterface
Anyways, I dont know how much of a good idea would it be to code a Multiple Data jointer, not just of 2 variables, but of many variables, maybe to put a System.currentTimeMillis() semaphore that identifies if incoming data is recieved within a very short span and joint them in a varArgs response once enough time has passed, it doesnt sound safe, but if one is sure of the order in which things will occur it may be handy.
As a final note:
the .wait() method, is not eternally bounded by the while's condition.
every time a notify(); is called (and this is the part that I'm not entirely sure), all the .wait()'s (inside a synchronized
method within the class(??)) are awaken, this means, that the logs where telling me that a notify indeed was being called, but the while loop is the one that forces the wait() to recheck the condition, and re-await.
Somewhere on a popular answer on this site, explaining the functionality of the locks waits and notifies, the user places a function inside the while loop, AFTER the try - catch.
You must be very careful, because the wait() may wake up whenever another thread calls a notify();
This kind of ambiguity is the one that made me use lock objects rather than use synchronous methods... their implementation is a bit more complex, but they feel more straightforward once (kind of) understood.