惰性值lazy
使用惰性值可以提高程序的性能
案例
假如我们对一个变量使用了lazy 则这个变量只有再被使用时才会执行初始化。
package study.ch_three
//演示代码1:
//init::::::
//start:::
//end:::
object lazyinitval {
def init(): Int = {
println("init::::::")
0
}
val resource: Int = init()
def main(args: Array[String]): Unit = {
println("start:::")
println("end:::")
}
}
//演示代码2:
//start:::
//init::::::
//end:::
object lazyinitval2 {
def init(): Int = {
println("init::::::")
0
}
lazy val resource: Int = init()
def main(args: Array[String]): Unit = {
println("start:::")
resource
println("end:::")
}
}
惰性值在多线程中会遇到的问题
由于惰性值在访问时才会进行初始话,可以缩短程序的执行事件進而提高效率;
问题:
-
但是在多线程-线程池中,如果多个线程都需要访问惰性值,此时惰性值就会频繁的进行初始话,从而影响效率。对于我来说,我只想让惰性值被线程池中的某一个线程初始话一次就够了,没必要多个线程,每访问一次都要初始化一次。
-
这个问题已经通过Scala(java同理)源码进行了解决(使用的是synchronized锁机制实现的),即一个线程池中的线程最多只会让一个线程初始化惰性值。
def execute (body: =>Unit) = ExecutionContext.global.execute{new Runnable {
override def run(): Unit = body
}}
/**
* * 但是在多线程-线程池中,如果多个线程都需要访问惰性值,此时惰性值就会频繁的进行初始话,从而影响效率。
* 对于我来说,我只想让惰性值被线程池中的某一个线程初始话一次就够了,没必要多个线程每访问一次都要初始化一次。
* 这个问题已经通过Scala源码进行了解决(使用的是this.synchronized锁机制实现的),即一个线程池中的线程最多只会让一个线程初始化惰性值。
**/
object two_惰性值在多线程中的问题和解决3 extends App {
lazy val obj = new AnyRef
lazy val non = s"made by:${Thread.currentThread().getName}"
execute {
println(s"线程池中的线程 obj = $obj")
println(s"线程池中的线程 non = $non")
}
println(s"main线程 obj = $obj")
println(s"main线程 non = $non")
Thread.sleep(2000)
}
避免惰性值之间出现循环依赖关系
惰性值之间的循环依赖关系:
1、 在单线程 (即顺序程序) 会出现堆栈溢出;
2、 多线程中会出现的死锁;
惰性值之间出现循环依赖关系(直接调用)
-
1、在并发程序中:
会出现死锁(因为lazy中有用到:this.synchronized锁机制) 当你的线程池中的线程调用惰性值A.x的时候,A对象会被进行监控; lazy的源码中是this.synchronized这里的this就是A对象,A对象被锁当你的main线程调用惰性值B.y的时候,B对象会被进行监控; 那么你想在A对象中使用B.y那就不可能了,因为此时B对象正在被main线程霸占着 -
2、在顺序环境中(即将execute { A.x }变成A.x):会出现堆栈溢出
-
3、在自己编写代码的时候尽量避免出现此类情况
object LazyValueDeadlock extends App {
def execute (body: =>Unit) = ExecutionContext.global.execute{new Runnable {
override def run(): Unit = body
}}
object A {
lazy val x: Int = B.y
}
object B {
lazy val y: Int = A.x
}
execute(A.x)
B.y
}
惰性值之间出现循环依赖关系(惰性值中使用线程操作)
我的main线程会先初始话惰性值x,同时通过synchronized进行当前对象的监控,然后执行里面的thread线程; thread线程因为要调用惰性值x,因此也会初始话惰性值x,但此时惰性值已经被main线程进行监控了, 所以就造成了死锁,或者说是堵塞。
object LazyValsAndBlocking extends App {
def thread(body: => Unit): Thread = {
val t = new Thread {
override def run(): Unit = body
}
t.start()
t
}
lazy val x: Int = {
val t = thread {
println(s"Initializing $x")
}
t.join()
1
}
x
}
惰性值之间出现循环依赖关系(synchronized中使用子线程)
我的main线程中使用了this.synchronized监听了this当前对象 而在this.synchronized中继续使用子线程调用惰性值x进行初始话的化,需要调用this当前对象,但是当前对象已经被main线程占用了,所以就出现死锁或者说是堵塞。
object LazyValsAndMonitors extends App {
def thread(body: => Unit): Thread = {
val t = new Thread {
override def run(): Unit = body
}
t.start()
t
}
lazy val x = 1
this.synchronized {
val t = thread {
x
}
t.join()
}
}
(本文章虽然采用的代码为scala代码,但java代码与Scala代码可以互相转换,且本质上两者所阐述的东西都是一致的)