How would you answer the following question?
A method of a java class contains a block of code that must be executed atomically. Explain, using appropriate pseudo-code, how you would ensure that this block of code is executed atomically
Would I achieve this by making the method ..
public final AtomicInteger x = new AtomicInteger(0);
then ensuring the get statement returned:
x.get()
and if I wanted to increment the value of x would I do this?
x.getAndIncrement();
The answer depends on your definition of "atomic"
I know of three valid definitions for atomic
:
The first is probably what your professor meant, and it's pretty easy to accomplish (see below).
The second (atomic as in ACID) can be approximated. See below.
The third simply cannot be guaranteed in Java - it doesn't provide access to the "critical sections" primitives required for uninterruptibility. Fortunately, the need for this is pretty much restricted to operating systems and device drivers.
Atomic as in synchronized
This is relatively straightforward: simply enclose your block of code in a synchronized block. I've shown it as a discrete block below, but there are other options:
public void doSomethingQuasiAtomic() {
synchronized (exampleLock) {
// Your code block goes here.
// Only one thread will ever be in this block at a time.
...
}
}
Atomic as in ACID
There's no general-case solution for ACID
atomicity, but it can be approximated, also using synchronized code. In order to do this, each of the parts of the action must be safely reversible.
This is how I'd approach it:
For the sake of argument, assume there's a multipart action you need to do on an object we'll call exampleObj
, that you have three actions to be performed which can be safely reversed, and that all access to example
is synchronized on exampleLock
.
synchronized(exampleLock) {
boolean actionOneDone=false;
boolean actionTwoDone=false;
boolean actionThreeDone=false;
try {
actionOneDone=doActionOne(exampleObj); // or perhaps exampleObj.doActionOne();
if(actionOneDone) actionTwoDone=doActionTwo(exampleObj);
if(actionTwoDone) actionThreeDone=doActionThree(exampleObj);
} catch (Exception ex) {
// Whatever seems appropriate here.
} finally {
if (! (actionOneDone && actionTwoDone && actionThreeDone)) {
/* At least one part failed. Back out the completed actions in reverse order.
* Note that we never need to reverse action three since if it completed, so did the others.
*/
if (actionTwoDone) {
reverseActionTwo(exampleObj); // or perhaps exampleObj.reverseActionTwo();
}
if (actionOneDone) {
reverseActionOne(exampleObj);
}
}
}
}
I believe that the expected answer was something like this:
public class A {
public void foo() {
// .. some code
doSomething(); // the critical part
// .. come code
}
public synchronized void doSomething() { // this is a synchronized method
// the critical code
}
}
The execution of doSomething()
is not really atomic (Disclaimer: it's very different from atomicity), but the synchronized keyword ensures that only one thread can enter the execution of this method (on one instance of A
). I think that is what they meant instead of atomicity.
Here is another question about atomicity in Java. You may find something useful in there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With