enl8enmentnow
enl8enmentnow

Reputation: 943

Kotlin synchronized inine

Is it known that you cannot synchronize an inlined function in Kotlin? I cannot find any documentation on this.

Imagine you have a class with a synchronized method;

/**
 * Allows modifying the value in a synchronized way so that the get() and set() are atomic.
 *
 * Note: anything synchronized cannot be `inline`.
 */
@Synchronized fun safeSet(calculateNewValue: (T) -> T) {
    set(calculateNewValue(get()))
}

When this function is inlined this test fails, when it is not inlined it passes.

@Test
fun `safeSet - is synchronized`() {
    val insideSet = AtomicInteger()
    val threadsRun = CountDownLatch(2)
    val t1 = Thread({
        threadsRun.countDown()
        sut.safeSet { currentValue: Int ->
            insideSet.incrementAndGet()
            try {
                Thread.sleep(100000)
            } catch (interrupted: InterruptedException) {
                BoseLog.debug(interrupted)
            }
            currentValue + 1
        }
    })
    t1.start()

    val t2 = Thread({
        threadsRun.countDown()
        sut.safeSet { currentValue: Int ->
            insideSet.incrementAndGet()
            try {
                Thread.sleep(100000)
            } catch (interrupted: InterruptedException) {
                BoseLog.debug(interrupted)
            }
            currentValue + 2
        }
    })
    t2.start()

    threadsRun.await()
    Thread.sleep(100)
    assertEquals(1, insideSet.get())
    t1.interrupt()
    t2.interrupt()
    Thread.sleep(100)
    assertEquals(2, insideSet.get())
}

Upvotes: 2

Views: 481

Answers (1)

yole
yole

Reputation: 97328

The @Synchronized annotation tells the compiler to generate the ACC_SYNCHRONIZED flag on the method. Inline functions are not compiled to methods, so the annotation is indeed ignored.

There is an open issue in Kotlin for handling this situation better.

Upvotes: 5

Related Questions