Java (可能)自定义ThreadPoolExecutor内存泄漏

Java (可能)自定义ThreadPoolExecutor内存泄漏,java,android,kotlin,Java,Android,Kotlin,为了在我的Android应用程序中集中后台线程处理,我定义了以下Runnable: class Task(private val runnable: Runnable) : Runnable { interface Callback { fun onTaskStarted() fun onTaskFinished() } var callback: Callback? = null override fun run() {

为了在我的Android应用程序中集中后台线程处理,我定义了以下
Runnable

class Task(private val runnable: Runnable) : Runnable {

    interface Callback {
        fun onTaskStarted()
        fun onTaskFinished()
    }

    var callback: Callback? = null

    override fun run() {
        callback?.run { mainHandler.post { this.onTaskStarted() } }
        runnable.run()
        callback?.run { mainHandler.post { this.onTaskFinished() } }

        // setting callback to null, so the Task instance can be garbage collected
        callback = null
    }

    companion object {
        private val mainHandler = Handler(Looper.getMainLooper())
    }
}
以及以下
ThreadPoolExecutor

class CustomThreadPoolExecutor :
        ThreadPoolExecutor(2, 2, 0L, TimeUnit.MILLISECONDS, LinkedBlockingQueue<Runnable>()),
        Task.Callback {

    val taskCount: MutableLiveData<Int> by lazy {
        MutableLiveData<Int>().apply { value = 0 }
    }

    fun executeTask(task: Task) {
        task.callback = this
        super.execute(task)
    }

    @MainThread
    override fun onTaskStarted() {
        taskCount.value = taskCount.value?.plus(1) ?: 1
    }

    @MainThread
    override fun onTaskFinished() {
        taskCount.value = taskCount.value?.minus(1) ?: 0
    }
}
其思想是将此执行器用于所有后台任务

可以观察
taskCount
对象,例如,根据当前是否有任务运行来显示/隐藏
ProgressBar

taskCount
对象只能从主线程访问,因此不应该存在任何并发问题(如果我错了,请纠正我)

回调
ThreadPoolExecutor
实例本身(它是一个单例),并且在任务完成后,引用将被清除,因此这也不应该是问题(再次,如果我错了,请纠正我)

问题:

要将数据插入数据库,我将调用我的
活动
(或
片段
)的以下方法

private fun saveTestData(测试项:列表){
customThreadPoolExecutor.executeTask(任务(可运行{
testService.saveAll(testItems)
}))
}
这里的
Runnable
是一个匿名的内部类,因此(我认为)包含了对所包含的
活动的引用

因此,
Runnable
(以及包装
任务
)无法进行垃圾收集,因此每次调用此方法时,实例计数都会增加(并且不会减少)

我的假设正确吗

如果是,我如何解决这个问题


(也欢迎Java回答)

为什么要无限期地保留该实例?在它执行之后,第二件事就是,将
ThreadPoolExecutor子类化是个坏主意。Kotlin为MarkoTopolnik提供了一流的功能。@MarkoTopolnik感谢您的回复。那么除了子类化之外,你认为这是一个可行的概念吗?或者你看到其他的缺陷了吗?如果这是我的项目,我会用协同程序来代替。我几乎不需要支持代码来实现它。非常简单的示例:
this.launch{initialStuff();val result=withContext(MyThreadPool){networkOperation()};updateGui(result)}
。这里
这应该是您的活动或实现
CoroutineScope
的片段。如果活动被销毁,它会自动取消所有后台任务。
@Provides
@Singleton
fun provideCustomThreadPoolExecutor(): CustomThreadPoolExecutor = CustomThreadPoolExecutor()
private fun saveTestData(testItems: List<TestItem>) {
    customThreadPoolExecutor.executeTask(Task(Runnable {
        testService.saveAll(testItems)
    }))
}