简体   繁体   中英

Concurrency in Kotlin

I have a class that has a nullable variable that is written by multiple thread, something like

class A {
    var s: String? = null //var accessed by multiple threads

    fun doStuff() {
        if (s != null) {
            //not safe
        }
    }
}

To counter this, I usually make an immutable copy like so

class A {
    var s: String? = null //var accessed by multiple threads

    fun doStuff() {
        val sCopy = s
        if (sCopy != null) {
            //safe now
        }
    }
}

I read about concurrency tools like volatile, synchronized etc but I'm not good at multithreading yet to know how should I handle it and I'm pretty sure there is better ways to achieve this than creating an immutable value, how would you do it?

You can simply reuse Java tooling in these cases.

For most simple cases, you would create an object (can be of any type) that will be used as the lock and use that lock for every single access to your state. There's the synchronized function which even let's you return a value directy:

val anyLock = Any()
fun syncWithArbitraryObjTest(): Int = synchronized(anyLock) { 123 }

Note that synchronized is a function in Kotlin which returns a value. This makes it more powerful than Java's synchronized keyword. Technically it doesn't make a difference on which object you lock, as long as you use the same object for all relevant code blocks that need be synchronized with each other.

If you choose to use a specific Lock object, eg an instance of ReentrantLock , you may use withLock instead:

val lock = ReentrantLock()
fun syncWithLockTest(): Int = lock.withLock { 123 }

Last but not least, your code val sCopy = s is no copy of s , it's simply a second variable pointing to the same object; this code isn't any safer.

You need to lock both the writes and the reads to your variable, like this:

class A {
    var s: String? = null //var accessed by multiple threads
     set(s) {
         synchronized(this) {
             field = s
         }
    }

    fun doStuff() {
        synchronized(this) {
            //safe now    
        }
    }
}

You need the synchronized in the setter beacuse otherwise the value might be overwritten while a thread is in doStuff.

Though in general it's better to avoid situations where multiple threads can write the same variable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM