非常感谢Zwei steinen编写了我使用的方法。我处理过的示例代码中存在一些问题,因此我认为值得在这里发表我的发现。
- 对join()的调用期望以毫秒为单位,而不是纳秒。
- 这两个线程必须协调,否则尝试线程可以在更衣室线程获取锁之前开始和结束所有线程。
- 直到我们记录了开始时间之后,才应该开始尝试线程。否则,该线程将获得足够的领先优势,以至于记录的时间可能比超时时间稍短,从而导致虚假故障。
这是作为Scala特性的同步测试代码:
trait SynchronizedTestTrait{ val classUnderTest: AnyRef class Gate { val latch = new java.util.concurrent.CountDownLatch(1) def open() { this.latch.countDown } def await() { this.latch.await } } def nanoTime(pre: => Unit) = { val before = System.nanoTime pre val after = System.nanoTime after - before } def assertSynchronized(pre: => Unit) { this.assertThreadSafety(threadSafe = true, millisTimeout = 10L)(pre) } def assertNotSynchronized(pre: => Unit) { this.assertThreadSafety(threadSafe = false, millisTimeout = 60L * 1000L)(pre) } def assertThreadSafety(threadSafe: Boolean, millisTimeout: Long)(pre: => Unit) { def spawn(pre: => Unit) = { val result = new Thread { override def run = pre } result.start() result } val gate = new Gate val lockHolderThread = spawn { this.classUnderTest.synchronized { // Don't let the other thread start until we've got the lock gate.open() // Hold the lock until interruption try { Thread.sleep(java.lang.Long.MAX_VALUE) } catch { case ignore: InterruptedException => return; } } } val measuredNanoTime = nanoTime { // Don't start until the other thread is synchronized on classUnderTest gate.await() spawn(pre).join(millisTimeout, 0) } val nanoTimeout = millisTimeout * 1000L * 1000L Assert.assertEquals( "Measured " + measuredNanoTime + " ns but timeout was " + nanoTimeout + " ns.", threadSafe, measuredNanoTime > nanoTimeout) lockHolderThread.interrupt lockHolderThread.join }}现在,我们要测试一个简单的类:
class MySynchronized{ def synch = this.synchronized{} def unsynch = {}}测试看起来是这样的:
class MySynchronizedTest extends SynchronizedTestTrait{ val classUnderTest = new MySynchronized @Test def synch_is_synchronized { this.assertSynchronized { this.classUnderTest.synch } } @Test def unsynch_not_synchronized { this.assertNotSynchronized { this.classUnderTest.unsynch } }}


