Home > database >  Android Runnable - Thread goes in sleeping state once code is executed, does not terminate
Android Runnable - Thread goes in sleeping state once code is executed, does not terminate

Time:06-20

I am creating a thread pool for running operations in background in an android app. Following is the code to create the thread pool and perform operations. Thread pool will be created only once but function gets called multiple times so multiple runnables are submitted to executor.

fun performOperation(){
    if(executorPool == null)
        executorPool = Executors.newCachedThreadPool()
    val runnable = Runnable{
                           //operations
                           }
    val future = executorPool!!.submit(runnable)
}

I am using cachedThreadPool. by definition it says:

Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available. These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks. Calls to execute will reuse previously constructed threads if available. If no existing thread is available, a new thread will be created and added to the pool. Threads that have not been used for sixty seconds are terminated and removed from the cache.

My expectation is once the operations are executed, my runnable thread should be terminated automatically after 60 seconds, but when I check in CPU profiler, runnable threads generated from here keep on increasing the times performOperation() function is called. In CPU profiler, I can see runnable threads going in sleeping state and not terminating(in Dead state).

I want to reduce the Thread count here, please guide me how should I proceed or how should I handle this.

CodePudding user response:

Try logging active thread count and thread pool size everytime you run an operation to be sure if that is the issue.

This is how I did it

class MainActivity : AppCompatActivity() {

    private var executorPool:ExecutorService? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        performOperation()

        var button = findViewById<Button>(R.id.button)

        button.setOnClickListener {

            val runnable = Runnable{
                Thread.sleep(1000)
                Log.e("msg","ok!")
                if (executorPool is ThreadPoolExecutor) {
                    Log.e("msg",(executorPool as ThreadPoolExecutor).poolSize.toString())
                }
            }

            val future = executorPool!!.submit(runnable)

        }


    }

    fun performOperation(){
        if(executorPool == null)
            executorPool = Executors.newCachedThreadPool()

    }
}

This is my logcat

2022-06-20 12:58:36.572 12493-12526/com.example.testkotlin E/msg: ok!
2022-06-20 12:58:36.572 12493-12526/com.example.testkotlin E/msg: 1
2022-06-20 12:58:38.699 12493-12526/com.example.testkotlin E/msg: ok!
2022-06-20 12:58:38.699 12493-12526/com.example.testkotlin E/msg: 3
2022-06-20 12:58:38.867 12493-12529/com.example.testkotlin E/msg: ok!
2022-06-20 12:58:38.867 12493-12529/com.example.testkotlin E/msg: 3
2022-06-20 12:58:39.055 12493-12530/com.example.testkotlin E/msg: ok!
2022-06-20 12:58:39.055 12493-12530/com.example.testkotlin E/msg: 3
2022-06-20 12:58:43.394 12493-12530/com.example.testkotlin E/msg: ok!
2022-06-20 12:58:43.394 12493-12530/com.example.testkotlin E/msg: 3
2022-06-20 12:59:20.868 12493-12530/com.example.testkotlin E/msg: ok!
2022-06-20 12:59:20.868 12493-12530/com.example.testkotlin E/msg: 3
2022-06-20 12:59:44.221 12493-12530/com.example.testkotlin E/msg: ok!
2022-06-20 12:59:44.221 12493-12530/com.example.testkotlin E/msg: 1

Here you can see after 1 minute thread pool size is 1 again after going upto 3

CodePudding user response:

Have you ever tryed kotlin coroutines? It faster and you doun't need use pool. Coroutines basics . Android include scopes for work in fragment like lifecycleScope and in viewModel like viewModelScope.
Also you can create scope with Dispatchers CoroutineScope(Dispatchers.IO) or connect in your coroutine launch(Dispatchers.IO){} You shold do something hard in Dispatchers.IO and change your views in Dispatchers.Main

You can read more here developer.android.com/kotlin/coroutines

You doun't need thread pool.
Just compare performance.

fun main() {
val count = 100000

thread(count)

//  runBlocking {
//      coroutine(count)
//  }
}

private fun thread(count: Int){
    for (i in 0 until count) {
        thread {
            Thread.sleep(1000)
            println(i)
        }
    }
}

private fun CoroutineScope.coroutine(count: Int){
    for (i in 0 until count) {
        launch(Dispatchers.Main) {
            delay(1000)
            println(i)
        }
    }
}
  • Related