I'm creating this method issueTransfer to achieve a transfer from one account to another.
My solution is:
public void issueTransfer(final int amount, final Account src,
final Account dst) {
/*
* TODO implement issueTransfer using object-based isolation instead of
* global isolation, based on the reference code provided in
* BankTransactionsUsingGlobalIsolation. Keep in mind that isolation
* must be applied to both src and dst.
*/
isolated(src, dst, () -> {
if (src.withdraw(amount)) {
dst.deposit(amount);
}
});
}
The solution for global isolation is:
public void issueTransfer(final int amount, final Account src,
final Account dst) {
isolated(() -> {
src.performTransfer(amount, dst);
});
}
The global and object isolated methods applied are defined like this:
public static void isolated(Runnable runnable) {
isolatedManager.acquireAllLocks();
try {
runnable.run();
} finally {
isolatedManager.releaseAllLocks();
}
}
public static void isolated(Object obj1, Object obj2, Runnable runnable) {
Object[] objArr = new Object[]{obj1, obj2};
isolatedManager.acquireLocksFor(objArr);
try {
runnable.run();
} finally {
isolatedManager.releaseLocksFor(objArr);
}
}
Helper methods (acquire and release) are:
public void acquireAllLocks() {
for(int i = 0; i < this.locks.length; ++i) {
this.locks[i].lock();
}
}
public void releaseAllLocks() {
for(int i = this.locks.length - 1; i >= 0; --i) {
this.locks[i].unlock();
}
}
public void acquireLocksFor(Object[] objects) {
TreeSet<Object> sorted = this.createSortedObjects(objects);
Iterator var3 = sorted.iterator();
while(var3.hasNext()) {
Object obj = var3.next();
int lockIndex = this.lockIndexFor(obj);
this.locks[lockIndex].lock();
}
}
public void releaseLocksFor(Object[] objects) {
TreeSet<Object> sorted = this.createSortedObjects(objects);
Iterator var3 = sorted.iterator();
while(var3.hasNext()) {
Object obj = var3.next();
int lockIndex = this.lockIndexFor(obj);
this.locks[lockIndex].unlock();
}
}
private int lockIndexFor(Object obj) {
return Math.abs(obj.hashCode()) % 64;
}
private TreeSet<Object> createSortedObjects(Object[] objects) {
TreeSet<Object> sorted = new TreeSet(new Comparator<Object>() {
public int compare(Object o1, Object o2) {
return IsolatedManager.this.lockIndexFor(o1) - IsolatedManager.this.lockIndexFor(o2);
}
});
Object[] var3 = objects;
int var4 = objects.length;
for(int var5 = 0; var5 < var4; ++var5) {
Object obj = var3[var5];
sorted.add(obj);
}
return sorted;
}
As you can see, I'm supposedly applying the 2nd method (object isolation) as required by the documentation. The test is passing without problems:
public void testObjectIsolation() {
testDriver(new BankTransactionsUsingGlobalIsolation());
final long globalTime = testDriver(
new BankTransactionsUsingGlobalIsolation());
testDriver(new BankTransactionsUsingObjectIsolation());
final long objectTime = testDriver(
new BankTransactionsUsingObjectIsolation());
final double improvement = (double)globalTime / (double)objectTime;
final int ncores = getNCores();
final double expected = (double)ncores * 0.75;
final String msg = String.format("Expected an improvement of at " +
"least %fx with object-based isolation, but saw %fx", expected,
improvement);
assertTrue(msg, improvement >= expected);
}
However the platform used for evaluation says I'm not passing the test either with 2 or 4 cores. Depending on when I do it, sometimes I pass 1 of the tests (I assume, the 2 cores test.
As you can see from the test that I pass, my object isolation solution is faster (in a 1:0.75 ratio per core) than my global isolation. Is it a platform failure or can my code be improved? I've tried using lock, unlock, and trylock, but my solution seems to work faster but not enough yet.
You could try this approach by Brian Goetz and Tim Pierels from the book, "Java Concurrency in Practice"