title: Why does using ExecutionContext causes this code not to halt?
body: <h2>The problem</h2>
  <p>I have an interesting instance of the producer–consumer problem in Scala written in two different ways. Both ways use <code>java.util.concurrent.ArrayBlockingQueue</code> as the buffer but they have the following differences:</p>
  <ul>
  <li><code>Version 1</code> starts the Producer and Consumer code as regular Java
  threads</li>
  <li><code>Version 2</code> starts the Producer and Consumer code using
  <code>ExecutionContext.global</code></li>
  </ul>
  <p>After executing both versions it can be clearly seen that <code>Version1</code> never finishes execution (because the number of consumers exceeds the number of producers, so at least one consumer keeps waiting indefinitely for new items to consume).</p>
  <p>However, the same is also the case in <code>Version2</code> i.e. the number of consumers also exceeds the number of producers, yet this time the program does finish its execution - <strong>the thing I'm asking for in this question is an explanation of why this is the case</strong>.</p>
  <h2>My attempt at the explanation</h2>
  <p>What I'd say is that even though the consumers in <code>Version2</code> also keep waiting for new items after the supply from producers &quot;dries up&quot;, the fact that the code is started within <code>ExecutionContext</code> means the code is run inside daemon threads, so after the main thread completes (here after artificially adding the <code>Thread.sleep(1000)</code> to prolong the execution), the daemon threads are stopped as well, regardless of whether they finished their main work or they keep waiting.</p>
  <p>However, I'm not sure if my explanation addresses the root of the problem and that it's not tangential. In other words, I'm not sure if I'm not stating something trivial but miss some obvious explanation of the problem. Could you please verify whether my general understanding is correct and if necessary help me find the proper explanation for this behavior of the two versions of the code? Thanks!</p>
  <h2>Code</h2>
  <pre><code>object Version1 extends App {
  
    class Producer(name: String, buffer: ArrayBlockingQueue[Integer]) extends Thread(name) {
      override def run(): Unit =
        for (i &lt;- 1 to 10) {println(s&quot;$getName produced $i&quot;); buffer.put(i)}
    }
  
    class Consumer(name: String, buffer: ArrayBlockingQueue[Integer]) extends Thread(name) {
      override def run(): Unit =
        for (_ &lt;- 1 to 10) println(s&quot;$getName consumed ${buffer.take}&quot;)
    }
  
    val buffer: ArrayBlockingQueue[Integer] = new ArrayBlockingQueue(5)
    for (i &lt;- 1 to 2) new Producer(s&quot;Producer$i&quot;, buffer).start()
    for (i &lt;- 1 to 3) new Consumer(s&quot;Consumer$i&quot;, buffer).start()
  
  }
  
  
  object Version2 extends App {
  
    val buffer: ArrayBlockingQueue[Integer] = new ArrayBlockingQueue(5)
    val ec = ExecutionContext.global
  
    for (p &lt;- 1 to 2)
      ec.execute(() =&gt; for (i &lt;- 1 to 10) {println(s&quot;Producer$p produced $i&quot;); buffer.put(i)})
  
    for (c &lt;- 1 to 3)
      ec.execute(() =&gt; for (_ &lt;- 1 to 10) {println(s&quot;Consumer$c consumed ${buffer.take}&quot;)})
  
    Thread.sleep(1000)
  
  }
  </code></pre>