Reputation: 24944
To my knowledge, in java, a static synchronized & a instance synchronized method won't effect each other's execution, since they lock on different object (this
instance vs the class
object itself).
In following code there are 2 sub threads, one runs a instance synchronized method, the other runs a static synchronized method.
Since ++
operator is not atomic, I am expecting following test case to pass (the final count should be less than the time ++
called), but it always fail the test (the final count equals to the time ++
called).
SyncInstanceAndStaticRelationshipLearn.java
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* Relationship of instance & static synchronized method.
*
* @author eric
* @date 1/3/19 9:32 PM
*/
public class SyncInstanceAndStaticRelationshipLearn {
private static final int ROUND = 1000;
private static final int INC_THREAD_COUNT = 2;
private static final long OPTIONAL_INC_DELAY = 1; // optional increase delay,
private static int N = 0;
@Test
public void test() throws InterruptedException {
ThreadGroup tg = new ThreadGroup("runner");
new Thread(tg, () -> {
try {
new MixedCounter().batchInsSync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "ts-inst").start();
new Thread(tg, () -> {
try {
MixedCounter.batchStaticSync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "ts-static").start();
Thread[] tArr = new Thread[INC_THREAD_COUNT];
tg.enumerate(tArr); // get threads,
// wait all runner to finish,
for (Thread t : tArr) {
t.join();
}
System.out.printf("\nfinal count: %d\n", getN());
// just check the output, and can see the instance & static methods mixed,
Assert.assertTrue(getN() < INC_THREAD_COUNT * ROUND);
}
public static int getN() {
return N;
}
// increase & print,
private static void incAndPrint() throws InterruptedException {
System.out.printf("[%s] start, N: %d\n", Thread.currentThread().getName(), getN());
N++;
Thread.sleep(OPTIONAL_INC_DELAY);
System.out.printf("[%s] end, N: %d\n", Thread.currentThread().getName(), getN());
}
// batch increase & print,
private static void batchInsAndPrint() throws InterruptedException {
for (int i = 0; i < ROUND; i++) {
incAndPrint();
}
}
// mixed instance / static counter,
static class MixedCounter {
public synchronized void batchInsSync() throws InterruptedException {
batchInsAndPrint();
}
public synchronized static void batchStaticSync() throws InterruptedException {
batchInsAndPrint();
}
}
}
[ts-inst] start, N: 0
[ts-static] start, N: 0
[ts-inst] end, N: 1
[ts-inst] start, N: 2
[ts-inst] end, N: 3
[ts-inst] start, N: 3
[ts-static] end, N: 2
[ts-inst] end, N: 4
[ts-inst] start, N: 4
[ts-inst] end, N: 5
[ts-inst] start, N: 5
[ts-inst] end, N: 6
[ts-inst] start, N: 6
[ts-inst] end, N: 7
[ts-inst] start, N: 7
[ts-inst] end, N: 8
[ts-inst] start, N: 8
[ts-static] start, N: 4
[ts-inst] end, N: 9
[ts-inst] start, N: 10
[ts-inst] end, N: 11
[ts-inst] start, N: 11
[ts-static] end, N: 10
...
[ts-inst] start, N: 1999
[ts-inst] end, N: 2000
final count: 2000
java.lang.AssertionError: expected [true] but found [false]
Expected :true
Actual :false
From the output, you can see that the 2 threads indeed mixed, but the final count is not less, even after increase the ROUND
to 1 million, it's still the same.
So, which part am I getting wrong?
Upvotes: 3
Views: 99
Reputation: 28289
System.out.printf
is synchronized
internally, though it does not gurantee a failed test, it might have influences.
You can try remove them to eliminate interference, like:
private static void incAndPrint() throws InterruptedException {
N++;
}
And this passed the test for some time on my computer:
final count: 1902
final count: 1111
final count: 1883
Upvotes: 1