```class MyObject private constructor() { comp...
# coroutines
k
Copy code
class MyObject private constructor() {
    companion object {
        @Volatile
        private var INSTANCE: MyObject? = null
        
        fun isReadyInstance(): Boolean {
            return (INSTANCE != null)
        }

        fun getInstance(): MyObject {
            return INSTANCE  ?: throw Exception("Error Instance is not initialized.")
        }

        fun createInstance() {
            synchronized(this) {
                if (INSTANCE == null) {
                    INSTANCE = MyObject()
                }
            }
        }

        fun deleteInstance() {
            synchronized(this) {
                INSTANCE = null
            }
        }
}
there is condition in my code to check for instance
Copy code
if (MyObject.isReadyInstance()) {
    MyObject.getInstance() //BUT HERE I GET -> "Error Instance is not initialized."
}
I think when
isReadyInstance
returned true meanwhile at some other place
deleteInstance
is called and therefore
getInstance
returned null, but how can i make sure that it won’t happen ?
k
Copy code
fun getInstance(): MiniGameManager {
    synchronized(this) {
       if (INSTANCE == null) {
          INSTANCE = MyObject()
       }
    }
    return INSTANCE
}
couldn't we make getInstance like this?
k
actually we are creating instance only once at specific position and check isReadyInstance before accessing it @Kunal Pasricha
a
Why not use `object`s for this?
k
actually while creating MyObject we need to pass some value in constructor() @andylamax
n
The separate
isReadyInstance
and
getInstance
methods are inherently unsafe. They would have to be combined like in your createInstance. Though, the simplest equivalent would just be:
Copy code
fun getInstanceOrNull(): MyObject? = INSTANCE
d
^^^ @Nick Allen to expand on nicks comment. This is unrelated to coroutines or flows , it is fundimental logic for any multithreaded appliation that between any 2 function calls - between any two statements (or most expressions) that 'anythign can happen' In general if you have a mutable variable var x = -1 and a test and mutator as seperate operations fun getX() = x fun setX(v: Int) { x = v } // convenience fun isInitialized() = (x >= 0 ) then between isInitialized() and getX() it is possible that setX() was called. that is fundimental to concurrency and threading in any software. To make the problem go away you have to have some form of locking or 'serialization ' (for all executables to run on one thread) or there simply is no way -- thats the definition of the language and its intentional. ( think: what if you NEEDED to assign X -- and the language prevented you -- what would you need to do to inform the language "Now is OK") so -- simply use one of the many patterns for concurrency -- your example is designed for threads so using synchronized blocks is fine. You just have to place BOTH the isReadyInstance() and getInstace() within the same synchronized block val instance = synchronized(this) { if( isReadyInstance() ) getInstance() else null )
current syncronized do nothing at all to protect two function calls only one