我该如何修复这个“不完全同步”的消费者生产者示例

时间:2011-07-08 12:06:25

标签: java multithreading scala synchronization reentrantlock

我正在尝试熟悉ReentrantLock和ConditionVariable类。我实现了这个Scala代码(其中没有任何“Scala特定”):

object Conditioned {

    var pops        = 0
    var max         = 20

    abstract class NamedThread extends Thread {
        def myName = this.toString
    }

    class Producer(lock:Lock,condition:Condition,source:ListBuffer[Int]) extends NamedThread {
        override def run = {
            var number   = max
            var current  = 0
            while(current < number) 
            {
                if(lock.tryLock)
                {
                    try
                    {
                        current += 1
                        source  += current
                        println("producer added data:"+current)
                        condition.signal
                    } finally { 
                        lock.unlock 
                        Thread.sleep(100)
                    }
                }
            }

        }
    }
class Consumer(lock:Lock,condition:Condition,source:ListBuffer[Int]) extends NamedThread {
        override def run = {
            while(pops < max) {
                println("awaiting")
                while(source.isEmpty)
                    condition.await
                println("consumer try lock")
                if(lock.tryLock)
                {
                    try {
                            val data = source(source.size - 1)
                            source  -= data
                            println("consumer received data:"+data+" hello from:"+myName)
                            pops += 1
                    } finally { lock.unlock }
               } 
            }            
        }
    }

    def main(args:Array[String]) = {
        val lock        = new ReentrantLock
        val condition   = lock.newCondition
        var lb          = new collection.mutable.ListBuffer[Int]()
        val producer    = new Producer(lock,condition,lb)
        val consumer    = new Consumer(lock,condition,lb)
        val cons2       = new Consumer(lock,condition,lb)
        val threads     = Array(producer,consumer,cons2)
        threads.foreach(_.start)
        threads.foreach(_.join)
    }
}

我试图在ListBuffer中生成20个元素,然后读取它们。我遗漏了一些东西,因为我的输出看起来像这样:

awaiting
consumer try lock
producer added data:1
awaiting
consumer try lock
consumer received data:1 hello from:Thread[Thread-51,5,trap.exit]
awaiting
awaiting
producer added data:2
producer added data:3
producer added data:4
producer added data:5
producer added data:6
producer added data:7
producer added data:8
producer added data:9
producer added data:10
producer added data:11
producer added data:12
producer added data:13
producer added data:14
producer added data:15
producer added data:16
producer added data:17
producer added data:18
producer added data:19
producer added data:20

但我不知道是什么。我正在使用一个ConditionVariable,这样我就可以在添加数据时向Consumer发出信号,但它似乎只能在第一次运行,之后生产者运行直到完成。我需要改变什么才能让它以消费者 - 生产者的方式运行,而不是以机器人工作者的方式运行? :)

1 个答案:

答案 0 :(得分:4)

您的消费者在持有锁时必须await (作为方法状态的javadocs)。

另外,您不应该使用tryLock,您应该只使用lock。如果您要进行其他,如果锁定获取失败,则仅使用tryLock。在您的情况下,如果锁定获取失败,您只需尝试再次获取它。