Concurrency and Parallelism

31.1 Threads and Java Concurrency

def t = Thread.start { println "Running in ${Thread.currentThread().name}" }
t.join()
Thread.startDaemon { /* background */ }

import java.util.concurrent.*
def pool = Executors.newFixedThreadPool(4)
def futures = (1..5).collect { n -> pool.submit({ n * n } as Callable) }
println futures*.get()
pool.shutdown()

def cf = CompletableFuture.supplyAsync { 21 }.thenApply { it * 2 }
println cf.get()

// Virtual threads (JDK 21+)
Executors.newVirtualThreadPerTaskExecutor().withCloseable { ex ->
    (1..1000).each { i -> ex.submit { Thread.sleep(10); i } }
}
Thread.ofVirtual().start { println "virtual thread" }.join()

31.2 Synchronization

import groovy.transform.Synchronized
import java.util.concurrent.atomic.AtomicInteger
class Counter {
    private int count = 0
    @Synchronized void inc() { count++ }
    int get() { count }
}
def atomic = new AtomicInteger()
(1..1000).collect { Thread.start { atomic.incrementAndGet() } }*.join()
println atomic.get()
def lock = new java.util.concurrent.locks.ReentrantLock()
lock.withLock { /* critical section (GDK helper) */ }

31.3 GPars (Groovy Parallel Systems)

GPars provides parallel collections, actors, agents, dataflow, and STM. It's in maintenance mode. For new code, consider Java's CompletableFuture, virtual threads, parallel streams, or Akka/Reactor.

@Grab('org.codehaus.gpars:gpars:1.2.1')
import static groovyx.gpars.GParsPool.withPool
import static groovyx.gpars.dataflow.Dataflow.task
import groovyx.gpars.actor.Actors

withPool(4) {
    println (1..10).collectParallel { it * it }
    println (1..100).findAllParallel { it % 7 == 0 }.sumParallel()
}

def actor = Actors.actor {
    loop { react { msg -> println "Got $msg"; if (msg == 'stop') terminate() } }
}
actor << "hello"
actor << "stop"
actor.join()

def v = new groovyx.gpars.dataflow.DataflowVariable()
task { v << 42 }
println v.val