@ -1,23 +1,60 @@
package org.session.libsignal.utilities
import android.os.Process
import java.util.concurrent.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.SynchronousQueue
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit
object ThreadUtils {
const val TAG = " ThreadUtils "
const val PRIORITY _IMPORTANT _BACKGROUND _THREAD = Process . THREAD _PRIORITY _DEFAULT + Process . THREAD _PRIORITY _LESS _FAVORABLE
val executorPool : ExecutorService = Executors . newCachedThreadPool ( )
// Paraphrased from: https://www.baeldung.com/kotlin/create-thread-pool
// "A cached thread pool such as one created via:
// `val executorPool: ExecutorService = Executors.newCachedThreadPool()`
// will utilize resources according to the requirements of submitted tasks. It will try to reuse
// existing threads for submitted tasks but will create as many threads as it needs if new tasks
// keep pouring in (with a memory usage of at least 1MB per created thread). These threads will
// live for up to 60 seconds of idle time before terminating by default. As such, it presents a
// very sharp tool that doesn't include any backpressure mechanism - and a sudden peak in load
// can bring the system down with an OutOfMemory error. We can achieve a similar effect but with
// better control by creating a ThreadPoolExecutor manually."
private val corePoolSize = Runtime . getRuntime ( ) . availableProcessors ( ) // Default thread pool size is our CPU core count
private val maxPoolSize = corePoolSize * 4 // Allow a maximum pool size of up to 4 threads per core
private val keepAliveTimeSecs = 100L // How long to keep idle threads in the pool before they are terminated
private val workQueue = SynchronousQueue < Runnable > ( )
val executorPool : ExecutorService = ThreadPoolExecutor ( corePoolSize , maxPoolSize , keepAliveTimeSecs , TimeUnit . SECONDS , workQueue )
// Note: To see how many threads are running in our app at any given time we can use:
// val threadCount = getAllStackTraces().size
@JvmStatic
fun queue ( target : Runnable ) {
executorPool . execute ( target )
executorPool . execute {
try {
target . run ( )
} catch ( e : Exception ) {
Log . e ( TAG , e )
}
}
}
fun queue ( target : ( ) -> Unit ) {
executorPool . execute ( target )
executorPool . execute {
try {
target ( )
} catch ( e : Exception ) {
Log . e ( TAG , e )
}
}
}
// Thread executor used by the audio recorder only
@JvmStatic
fun newDynamicSingleThreadedExecutor ( ) : ExecutorService {
val executor = ThreadPoolExecutor ( 1 , 1 , 60 , TimeUnit . SECONDS , LinkedBlockingQueue ( ) )