Improve JavaPluginScheduler

This commit is contained in:
Him188 2020-05-23 18:45:56 +08:00
parent a861b73cc7
commit d37d6881fc
2 changed files with 86 additions and 149 deletions

View File

@ -1,149 +0,0 @@
package net.mamoe.mirai.console.scheduler
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import net.mamoe.mirai.console.plugins.PluginBase
import java.util.concurrent.Future
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import java.util.function.Supplier
import kotlin.coroutines.CoroutineContext
/**
* 作为Java插件开发者, 你应该使用PluginScheduler
* 他们使用kotlin更高效的协程实现并在API上对java有很高的亲和度
* 且可以保证在PluginBase关闭的时候结束所有任务
*
* 你应该使用SchedulerTaskManager获取PluginScheduler, 或直接通过PluginBase获取
*/
class PluginScheduler(_coroutineContext: CoroutineContext) : CoroutineScope {
override val coroutineContext: CoroutineContext = _coroutineContext + SupervisorJob(_coroutineContext[Job])
class RepeatTaskReceipt(@Volatile var cancelled: Boolean = false)
/**
* 新增一个 Repeat Task (定时任务)
*
* 这个 Runnable 会被每 [intervalMs] 调用一次(不包含 [runnable] 执行时间)
*
* 使用返回的 [RepeatTaskReceipt], 可以取消这个定时任务
*/
fun repeat(runnable: Runnable, intervalMs: Long): RepeatTaskReceipt {
val receipt = RepeatTaskReceipt()
this.launch {
while (isActive && (!receipt.cancelled)) {
withContext(Dispatchers.IO) {
runnable.run()
}
delay(intervalMs)
}
}
return receipt
}
/**
* 新增一个 Delay Task (延迟任务)
*
* 在延迟 [delayMs] 后执行 [runnable]
*
* 作为 Java 使用者, 你要注意可见性, 原子性
*/
fun delay(runnable: Runnable, delayMs: Long) {
this.launch {
delay(delayMs)
withContext(Dispatchers.IO) {
runnable.run()
}
}
}
/**
* 异步执行一个任务, 最终返回 [Future], Java 使用方法无异, 但效率更高且可以在插件关闭时停止
*/
fun <T> async(supplier: Supplier<T>): Future<T> {
return AsyncResult(
this.async {
withContext(Dispatchers.IO) {
supplier.get()
}
}
)
}
/**
* 异步执行一个任务, 没有返回
*/
fun async(runnable: Runnable) {
this.launch {
withContext(Dispatchers.IO) {
runnable.run()
}
}
}
}
/**
* 这个类作为 Java Kotlin 的桥接
* Java interface 进行了 Kotlin 的实现
* 使得 Java 开发者可以使用 Kotlin 的协程 [CoroutineScope.async]
* 具体使用方法与 Java [Future] 没有区别
*/
class AsyncResult<T>(
private val deferred: Deferred<T>
) : Future<T> {
override fun isDone(): Boolean {
return deferred.isCompleted
}
override fun get(): T {
return runBlocking {
deferred.await()
}
}
@OptIn(ExperimentalCoroutinesApi::class)
override fun get(p0: Long, p1: TimeUnit): T {
return runBlocking {
withTimeoutOrNull(p1.toMillis(p0)) {
deferred.await()
} ?: throw TimeoutException()
}
}
override fun cancel(p0: Boolean): Boolean {
deferred.cancel()
return true
}
override fun isCancelled(): Boolean {
return deferred.isCancelled
}
}
internal object SchedulerTaskManagerInstance {
private val schedulerTaskManagerInstance = mutableMapOf<PluginBase, PluginScheduler>()
private val mutex = Mutex()
fun getPluginScheduler(pluginBase: PluginBase): PluginScheduler {
runBlocking {
mutex.withLock {
if (!schedulerTaskManagerInstance.containsKey(pluginBase)) {
schedulerTaskManagerInstance[pluginBase] = PluginScheduler(pluginBase.coroutineContext)
}
}
}
return schedulerTaskManagerInstance[pluginBase]!!
}
}

View File

@ -0,0 +1,86 @@
package net.mamoe.mirai.console.utils
import kotlinx.coroutines.*
import kotlinx.coroutines.future.future
import net.mamoe.mirai.console.plugins.builtin.JavaPlugin
import java.util.concurrent.Callable
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Future
import kotlin.coroutines.CoroutineContext
/**
* 拥有生命周期管理的 Java 线程池.
*
* 在插件被 [卸载][JavaPlugin.onDisable] 时将会自动停止.
*
* @see JavaPlugin.scheduler 获取实例
*/
class JavaPluginScheduler internal constructor(parentCoroutineContext: CoroutineContext) : CoroutineScope {
override val coroutineContext: CoroutineContext =
parentCoroutineContext + SupervisorJob(parentCoroutineContext[Job])
/**
* 新增一个 Repeating Task (定时任务)
*
* 这个 Runnable 会被每 [intervalMs] 调用一次(不包含 [runnable] 执行时间)
*
* @see Future.cancel 取消这个任务
*/
fun repeating(intervalMs: Long, runnable: Runnable): Future<Void?> {
return this.future {
while (isActive) {
withContext(Dispatchers.IO) { runnable.run() }
delay(intervalMs)
}
null
}
}
/**
* 新增一个 Delayed Task (延迟任务)
*
* 在延迟 [delayMillis] 后执行 [runnable]
*/
fun delayed(delayMillis: Long, runnable: Runnable): CompletableFuture<Void?> {
return future {
delay(delayMillis)
withContext(Dispatchers.IO) {
runnable.run()
}
null
}
}
/**
* 新增一个 Delayed Task (延迟任务)
*
* 在延迟 [delayMillis] 后执行 [runnable]
*/
fun <R> delayed(delayMillis: Long, runnable: Callable<R>): CompletableFuture<Void?> {
return future {
delay(delayMillis)
withContext(Dispatchers.IO) { runnable.call() }
null
}
}
/**
* 异步执行一个任务, 最终返回 [Future], Java 使用方法无异, 但效率更高且可以在插件关闭时停止
*/
fun <R> async(supplier: Callable<R>): Future<R> {
return future {
withContext(Dispatchers.IO) { supplier.call() }
}
}
/**
* 异步执行一个任务, 没有返回
*/
fun async(runnable: Runnable): Future<Void?> {
return future {
withContext(Dispatchers.IO) { runnable.run() }
null
}
}
}