Java同步死锁?

Java同步死锁?,java,scala,Java,Scala,我对Java并发性非常陌生,我一直在试图用锁和监视器来解决一个小问题。问题的要点是我有一个类,它有get和put方法,本质上是线程消费和生成的容器。就我的一生而言,我无法正确地进行同步,结果要么死锁,要么出现IllegalMonitorStateException package concurrency object ThreadsMain extends App { val syncVar = new SyncVar[Int]() val producer = new Thread

我对Java并发性非常陌生,我一直在试图用锁和监视器来解决一个小问题。问题的要点是我有一个类,它有
get
put
方法,本质上是线程消费和生成的容器。就我的一生而言,我无法正确地进行同步,结果要么死锁,要么出现
IllegalMonitorStateException

package concurrency

object ThreadsMain extends App {
  val syncVar = new SyncVar[Int]()

  val producer = new Thread {
    override def run(): Unit = {
      for (x <- 1 to 15) {
        syncVar.synchronized {
          if (!syncVar.isEmpty) {
            syncVar.wait()
          } else {
            syncVar.put(x)
            syncVar.notify()
          }
        }
      }
    }
  }

  producer.run()

  val consumer = new Thread {
    this.setDaemon(true)

    override def run(): Unit = {
      while (true) {
        syncVar.synchronized {
          if (syncVar.isEmpty) {
            syncVar.wait()
          } else {
            println(syncVar.get())
            syncVar.notify()
          }
        }
      }
    }
  }

  consumer.run()

  producer.join()

  consumer.join()
}

class SyncVar[T]() {
  var isEmpty: Boolean = true
  var value: Option[T] = None

  def get(): T = {
    if (isEmpty) throw new Exception("Get from empty SyncVar")
    else {
      val toReturn = value.get
      value = None
      isEmpty = true
      toReturn
    }
  }

  def put(x: T): Unit = {
    if (!isEmpty) throw new Exception("Put on non-empty SyncVar")
    else {
      value = Some(x)
      isEmpty = false
    }
  }
}
包并发
对象线程在应用程序中扩展{
val syncVar=new syncVar[Int]()
val producer=新线程{
覆盖def run():单位={

对于(x有几个问题:

  • 您应该在非
    run
    上使用
    start
  • 如果您使用的是
    join
    ,则没有必要将tread设置为守护进程线程
  • 当你在制作人中做
    if…else
    时,你只得到奇数。它应该是
    if
    ,其余的在
    if
    之后(实际上
    是一个更好的做法)
  • 我认为通过这种方式,代码可以满足您的要求:

    object ThreadsMain extends App {
      val syncVar = new SyncVar[Int]()
      val isDone = new AtomicBoolean(false)
    
      val producer = new Thread {
        override def run(): Unit = {
          for (x <- 1 to 15) {
            syncVar.synchronized {
              while (!syncVar.isEmpty) {
                syncVar.wait()
              }
              syncVar.put(x)
              syncVar.notify()
            }
          }
          isDone.set(true)
        }
      }
    
      producer.start()
    
      val consumer = new Thread {
    
        override def run(): Unit = {
          while (!isDone.get()) {
            syncVar.synchronized {
              while (syncVar.isEmpty) {
                syncVar.wait()
              }
              println(syncVar.get())
              syncVar.notify()
            }
          }
        }
      }
    
      consumer.start()
    
      producer.join()
    
      consumer.join()
    }
    
    class SyncVar[T]() {
      var isEmpty: Boolean = true
      var value: Option[T] = None
    
      def get(): T = {
        if (isEmpty) throw new Exception("Get from empty SyncVar")
        else {
          val toReturn = value.get
          value = None
          isEmpty = true
          toReturn
        }
      }
    
      def put(x: T): Unit = {
        if (!isEmpty) throw new Exception("Put on non-empty SyncVar")
        else {
          value = Some(x)
          isEmpty = false
        }
      }
    }
    
    对象线程main扩展应用程序{
    val syncVar=new syncVar[Int]()
    val isDone=新原子布尔值(false)
    val producer=新线程{
    覆盖def run():单位={
    
    对于(x多线程是最难编写的代码之一。你是Java新手吗?我建议不要使用这种低级Java 1.0结构。看看Java.util.concurrency和Executor类。它们是对臭名昭著的困难基类的改进。@duffymo我这么做纯粹是为了更好地理解高级Java 1.0结构是什么er级抽象正在幕后进行。这只是一个学习练习:)尝试调用start()而不是run()来实际启动线程。谢谢@rustyx!这让我松了一口气。也许在一个只有一个生产者和一个消费者的玩具示例中,你可以不受惩罚。但在现实生活中,将呼叫包装为在if中而不是在循环中等待会导致问题。请参阅