kotlin并发性
新开始读G. Blake Meike写的"Android Concurrency",到目前为止我非常推荐这本伟大的书,
它包含了许多关于不同的Android并发机制如何工作的深刻见解,当您更喜欢一种实现方式而不是另一种实现方式时,如何获得最好的方法。
我决定学习书中的例子,并且重写这些例子。由于我非常地热爱kotlin,我觉得把这些例子用kotlin实现是个不错的主意。
在Android Concurrency书的第一章,作者使用java中最基本的并发语法,因此现在我开始使用kotlin书写这些代码例子,我非常惊奇的发现:
在kotlin中没有synchronized 关键字
在kotlin中没有volatile 关键字
kotlin中的Any和java中的Object相似,但是没有wait(), notify() 和 notifyAll() 三个方法
那么并发是如何在kotlin中工作的呢?这个问题已经在kotlin forum中被问到了。如下是kotlin项目leader Andrey Breslav的回答:
Kotlin故意没有构建语言的并发性。我们认为这应该由libraries来处理。
尽管kotlin没有把并发性内置在语音中,但是仍然提供了很多低语言的并发语法。现在,让我们来看看这些语法。
Creating Threads
在java中有两种方法创建一个线程:
1:扩展Thread类
2:实例化Thread类并且通过构造函数传入一个Runnable
因为你能够kotlin中简单的使用java 类,上述两种方法也可以很好的起作用。
下面展示如下子类化Thread:
object : Thread() { override fun run() { println("running from Thread:${Thread.currentThread()}") } }.start()
这部分代码使用到了kotlin的Object 表达式创建匿名类,并且重写了run()方法。此处将会演示如何传入一个Runnable对象来创建Thread的实例:
Thread({ println("running from lambda:${Thread.currentThread()}") }).start()
在这你并没有看到Runnable对象,在kotlin中你能够很容易的使用lambda表达式。是否还有更好的方法呢?当然!下面将会演示如果使用kotlin风格实例化并且启动一个线程:
thread(start=true) { println("running from thread():${Thread.currentThread()}") }
很简洁,不是么?我们正在使用thread()方法,它会神奇地隐藏所有的样板代码。事实上,下面将展示完成的thread()方法:
public fun thread(start: Boolean = true, isDaemon: Boolean = false, contextClassLoader: ClassLoader? = null, name: String? = null, priority:Int = -1, block: () -> Unit) : Thread { val thread = object: Thread() { public override fun run() { block() } } if (isDaemon) thread.isDaemon = true if (priority > 0) thread.priority = priority if (name != null) thread.name = name if(contextClassLoader != null) thread.contextClassLoader = contextClassLoader if(start) thread.start() return thread }
它只是一个非常方便的包装函数,使用起来很方便。
Synchronized Methods and Blocks
在kotlin中,synchronized不是一个关键字,使用@Synchronized注解。
在kotlin中一个synchronized方法的声明看起来如下所示:
@Synchronized fun synchronizedMethod() { println("inside a synchronized method:${Thread.currentThread()}") }
这个注解和Java中的synchronized有同样的效果:它将把JVM方法标记为同步。对应同步代码块,你不得不使用synchronized()方法,这将会使用一个lock作为一个参数:
fun methodWithSynchronizedBlock() { println("outside of a synchronized block:${Thread.currentThread()}") synchronized(this) { println("inside a synchronized block:${Thread.currentThread()}") } }
代码的外观和行为与Java变量非常相似。
Volatile Fields
同样地,在kotlin中没有volatile关键字,但是有@Volatile注解,
@Volatile private var running = false fun start() { running = true thread(start = true) { while(running) { println("Still running:${Thread.currentThread()}") } } } fun stop() { running = false println("Stopped:${Thread.currentThread()}") }
和@Synchronized是相似的,@Volatile将把JVM支持字段标记为volatile。
wait(), notify() and notifyAll()
在kotlin中,每一个类都是从Any继承过来的,但是Any并没有声明wait(),notify()和notifyAll()方法,这就意味着,你不能在kotlin类中调用这些方法。但是你仍然能够使用java.lang.Object的实例作为lock,并且调用相关的方法。下面将会展示一个使用Objec做为lock解决生产者和消费者的问题,
private val lock = java.lang.Object() fun produce() = synchronized(lock) { while(items>=maxItems) { lock.wait() } Thread.sleep(rand.nextInt(100).toLong()) items++ println("Produced, count is$items:${Thread.currentThread()}") lock.notifyAll() } fun consume() = synchronized(lock) { while(items<=0) { lock.wait() } Thread.sleep(rand.nextInt(100).toLong()) items-- println("Consumed, count is$items:${Thread.currentThread()}") lock.notifyAll() }
Does it look hacky? Well, it is(译者注:不是很明白)
事实是如果在你的代码中使用如此low-level constructs,看起来正在做一些错误的事情了。如今无论是在java中还是kotlin中都有很多高级的并发机制满足每一个需求,在Stackoverflow上面有一个非常棒的回答,并且提供了一系列可用的工具来写并发代码。
文章中的代码已经发布到GitHub,请参考。
Conclusion
尽快在项目中不会被频繁地使用到,但是了解和理解基础的知识还是比较重要的。最终发现在kotlin和java还是有一些不同的地方,但是主要的机制是一样的。请记住,kotlin和java的交互时候非常棒的,所以如果kotlin 没有counterparts,你就可以依赖Java类。玩得开心!
原文地址链接:https://blog.egorand.me/concurrency-primitives-in-kotlin/