Background
I've found some GIF animation library, which has a background thread that constantly decodes the current frame into a bitmap, being a producer to other thread :
@Volatile
private var mIsPlaying: Boolean = false
...
while (mIsRunning) {
if (mIsPlaying) {
val delay = mGifDecoder.decodeNextFrame()
Thread.sleep(delay.toLong())
i = (i + 1) % frameCount
listener.onGotFrame(bitmap, i, frameCount)
}
}
The sample POC I've made for this is available here.
The problem
This is inefficient, because when the thread gets to a point that mIsPlaying
is false, it just waits there and constantly checks it. In fact, it causes this thread to do more CPU usage somehow (I checked via the profiler).
In fact, it goes from 3-5% of CPU, to 12-14% CPU.
What I've tried
I had a good knowledge about threads in the past, and I know that simply putting a wait
and notify
is dangerous as it could still cause the thread to wait on some rare cases. For example when it identified that it should wait, and then before it starts to wait, the outside thread marks it that it shouldn't wait.
This behavior is called "busy spinning" or "Busy Waiting" , and there are actually some solutions about it, in the case of multiple threads that need to work together, here .
But here I think it's a bit different. The wait isn't for some thread to finish its work. It's for temporary waiting.
Another issue here is that the consumer thread is the UI thread, as it is the one that needs to get the bitmap and view it, so it can't just wait work like a consumer-producer solution (UI must never wait, as it can cause "jank") .
The question
What's the proper way to avoid spinning here?