Scala版的生产者消费者模型&泛型中的协变(Covariance)与逆变(Contravar...

class BoundedBuffer[A : ClassManifest](N: Int) {
	var in = 0
	var out = 0
	var n = 0
	
	val elems = new Array[A](N)
	
	def put(x: A) = synchronized {
		while (n >= N) wait()
		elems(in) = x
		in = (in + 1) % N
		n = n + 1
		
		if (n == 1) notifyAll()
	}
	
	def get: A = synchronized {
		while (n == 0) wait()
		var x = elems(out)
		out = (out + 1) % N
		n = n - 1
		if (n == N - 1) notifyAll()
		x
	}
}

object Tester {
	var no = 0
	def spawn(p: => Unit) {
		val t = new Thread() { override def run() = p }
		t.start()
	}
	
	def produceString : String = {
		no += 1
		"Hello World" + no
	}
	  
	def consumeString(str : String) = println(str)
	
	def main(args: Array[String]) { 
		val buf = new BoundedBuffer[String](10)
		spawn {
			while (true) {
				val s = produceString
				buf.put(s)
			}
		}
		
		spawn {
			while (true) {
				val s = buf.get
				consumeString(s)
			}
		}
	} 
}

先上代码再分析

1. 从线程同步的角度看,Scala对并发的支持与Java是一样的,支持如下同步原语:

  • def synchronized[A] (e: => A): A
  • def wait()
  • def wait(msec: Long)
  • def notify()
  • def notifyAll()

2. Scala泛型,以及泛型中的协变(Covariance)与逆变(Contravariance)

    如果将

class BoundedBuffer[A : ClassManifest](N: Int)

改为

class BoundedBuffer[A](N: Int)

是编译不过的。为了能够在运行时判断类型,以及避免类型错误的异常情况,Scala的Array要求对类型有个不透明的描述。其实就是一个trait。Scala API给了解释:

A ClassManifest[T] is an opaque descriptor for type T. It is used by the compiler to preserve information necessary for instantiating Arrays in those cases where the element type is unknown at compile time.The type-relation operators make an effort to present a more accurate picture than can be realized with erased types, but they should not be relied upon to give correct answers. In particular they are likely to be wrong when variance is involved or when a subtype has a different number of type arguments than a supertype.

这样精细的控制,有利于写出更加安全的代码。

    协变是指将子类容器赋值给基类容器,逆变指将基类容器赋值给子类容器。这两种行为在Scala中默认都是不允许的。但实际应用中肯定会遇到需要在类层次的不同高度操作的问题。

    有两种方法实现协变和逆变:

    1. 定义容器时,不使用[T],而使用[+T]或[-T],分别允许协变和逆变。

    2. 使用时,定义类型的上界和下界。类似于[T <: Person],定义上界,这就要求参数至少是Person,它的子类容器也是可以的。类似于,[T >: S],定义下界,限制类型为S或者S的父类。

你可能感兴趣的:(Scala版的生产者消费者模型&泛型中的协变(Covariance)与逆变(Contravar...)