多线程的设计,在遇到需要多个执行IO操作的时候,多个线程的阻塞,造成了效率的下降,这个时候异步就是不错的选择了。
注意:下面许多操作都是新的库,比旧的版本可能没有。
- 异步
- 协程
示例:
fun main(args:Array<String>) {
//创建异步操作
val job = launch(
search()
)
println("Hello, ")
//等待job执行结束,程序结束
job.join()
}
suspend fun search(){
//delay只能在协程内部或者suspend函数中执行
delay(1000L)
println("World!")
}
- 同步方式写异步代码
实例:
fun main(args:Array<String>)= runBlocking<Unit>{
val one = async{ searchItemOne() }
val two = async{ searchItemTwo() }
println("The item is ${one.await()} and ${two.await()}")
}
- 并发
使用@Synchronized保证整个函数或者synchronized()保证一部分代码块。
class Shop{
val goods = hashMapOf<Long, Int>()
init {
goods.put(1, 10)
goods.put(2, 15)
}
@Synchronized fun buyGoods(id: Long){
val stock = goods.getValue(id)
goods.put(id, stock - 1)
}
fun buyGoods2(id: Long){
synchronized(this){
val stock = goods.getValue(id)
goods.put(id, stock - 1)
}
}
}
另外,Kotlin中的Akka也是基于Actor的不错的选择。
- Akka
Akka共享内存的设计理念和传统不同,Actor模型提倡的是:通过通信来实现共享内存,而不是共享内存来实现通信。
原则:
- 消息的发送必须先于消息的接收。
- 同一个Actor对一条消息的处理先于对于下一条消息的处理。
示例:
import akka.actor.ActorRef
import akka.actor.ActorSystem
import akka.actor.Props
import akka.actor.UntypedAbstractActor
import akka.pattern.Patterns
import akka.util.Timeout
import scala.concurrent.Await
import scala.concurrent.duration.Duration
import java.util.*
class ShopActor(val stocks:HashMap<Long, Int>):UntypedAbstractActor(){
var orderNumber = 1L
override fun onReceive(message: Any?){
when(message){
is Action.Buy -> {
val stock = stock.getValue(message.id)
if(stock > message.amount){
stocks.plus(Pair(message.id, stock - message.amount))
sender.tell(orderNumber, self)
orderNumber++
} else {
sender.tell("low stock", self)
}
}
is Action.GetStock -> {
sender.tell(stocks.get(message.id), self)
}
}
}
}
sealed class Action{
data class BuyOrInit(...):Action()//参数省略
data class Buy(val id:Long, val userId:Long, val amount:Long):Action()
data class GetStock(val id:Long):Action()
data class GetStockOrInit(....)
}
class ManageActor: UntypedAbstractActor(){
override fun onReceive(message: Any?){
when(message){
is Action.BuyOrInit -> getOrInit(message.shopName, message.stocks).forward(Action.Buy(message.id, message.userId, message.amount), context)
is Action.GetStockOrInit -> getOrInit(message.shopName,message.stocks).forward(Action.GetStock(message.id), context)
}
}
fun getOrInit(shopName:String, stocks:Map<Long, Int>:ActorRef{
return context.findChild("shop-actor-${shopName}").orElseGet{context.actorOf(Props.create(ShopActor::class.java, stocks), "shop-actor-${shopName}")}
}
}
fun main(args:Array<String>){
val stocksA = hashMapOf(Pair(1L, 10), Pair(2L, 5), Pair(3L, 20))
val stockB = hashMapOf(Pair(1L, 15), Pair(2L, 8), Pair(3L, 30))
val actorSystem = ActorSystem.apply("shop-system")
val manageActor = actorSystem.actorOf(Props.create(ManageActor::class.java),"manage-actor")
val timeout = Timeout(Duration.create(3, "second")
val resA = Patterns.ask(manageActor, Action.GetStockOrInit(1L, "A", stocksA), timeout)
val stock = Await.result(resA, timeout.duration())
println("the stock is ${stock}")
val resB = Patterns.ask(manageActor, Action.BuyOrInit(2L, 1L, 1, "b", stocksB), timeout)
val orderNumber = Await.result(resB, timeout.duration())
println("the orderNumber is ${orderNumber}")
}