测试Java方法是否同步的好方法是什么? [英] What is a good way to test that a Java method is synchronized?

查看:181
本文介绍了测试Java方法是否同步的好方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有几个实现某个接口的类。接口有一个契约,有些方法应该同步,有些不应该,我想通过单元测试来验证所有实现的合同。这些方法应该使用synchronized关键字或者锁定在这个 - 非常类似于synchronizedCollection()包装器。这意味着我应该能够在外部观察它。

I have several classes that implement some interface. The interface has a contract, that some methods should be synchronized, and some should not, and I want to verify that contract through unit tests for all the implementations. The methods should use the synchronized keyword or be locked on this - very similar to the synchronizedCollection() wrapper. That means I should be able to observe it externally.

继续 Collections.synchronizedCollection()如果我有一个线程调用iterator(),我应该仍然是能够使用另一个线程进入add()等方法,因为iterator()不应该进行任何锁定。另一方面,我应该能够在外部同步集合并看到另一个线程阻塞在add()上。

To continue the example of Collections.synchronizedCollection() if I have one thread calling iterator(), I should still be able to get into methods like add() with another thread because iterator() should not do any locking. On the other hand, I should be able to synchronize on the collection externally and see that another thread blocks on add().

有没有一个很好的方法测试一个方法在JUnit测试中是否同步?我想避免长时间的睡眠陈述。

推荐答案

非常感谢Zwei steinen撰写方法我用过的。在我完成的示例代码中存在一些问题,所以我认为值得在此发布我的调查结果。

A big thank you to Zwei steinen for writing up the approach I used. There are a few problems in the example code that I worked through, so I thought it would be worth posting my findings here.


  • 电话会议join()需要几毫秒,而不是纳秒。

  • 必须协调两个线程,否则尝试线程可以在锁定线程获取锁之前启动和完成所有线程。

  • 在记录开始时间之前,不应启动尝试线程。否则该线程会有足够的启动时间,记录的时间可能会略微超过超时,从而导致虚假失败。

这是同步测试代码为Scala特征:

Here is the synchronization test code as a Scala trait:

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(code: => Unit) =
    {
        val before = System.nanoTime
        code
        val after = System.nanoTime
        after - before
    }

    def assertSynchronized(code: => Unit)
    {
        this.assertThreadSafety(threadSafe = true, millisTimeout = 10L)(code)
    }

    def assertNotSynchronized(code: => Unit)
    {
        this.assertThreadSafety(threadSafe = false, millisTimeout = 60L * 1000L)(code)
    }

    def assertThreadSafety(threadSafe: Boolean, millisTimeout: Long)(code: => Unit)
    {
        def spawn(code: => Unit) =
        {
            val result = new Thread
            {
                override def run = code
            }
            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(code).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
    }
}

现在假设我们要测试一个简单的类:

Now let's say we want to test a simple class:

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
        }
    }
}

这篇关于测试Java方法是否同步的好方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆