据我所知,在Java中,静态同步和实例同步方法不会影响彼此的执行,因为它们锁定在不同的对象上(this
实例与class
对象本身)。
在下面的代码中,有2个子线程,一个运行实例同步方法,另一个运行静态同步方法。
由于++
运算符不是原子运算符,我希望以下测试用例通过(最终计数应小于调用++
的时间),但始终测试失败(最终计数等于调用时间++
)。
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
从输出中,您可以看到2个线程确实混合在一起,但是最终计数仍然不少,即使将ROUND
增加到100万,它仍然是相同的。
那我错了哪一部分?
答案 0 :(得分:1)
System.out.printf
在内部是synchronized
,尽管它不能保证测试失败,但可能会产生影响。
您可以尝试删除它们以消除干扰,例如:
private static void incAndPrint() throws InterruptedException {
N++;
}
这在我的计算机上通过了一段时间的测试:
final count: 1902
final count: 1111
final count: 1883