concurrency and threading
Rava2 provides native support for Java's threading model, mapping java.lang.Thread to POSIX pthreads with full monitor synchronization.
thread states
Threads progress through a defined state lifecycle:
| state | description |
|---|---|
THREAD_NEW | Created but not yet started |
THREAD_RUNNABLE | Executing or ready to execute |
THREAD_BLOCKED | Waiting to acquire a monitor lock |
THREAD_WAITING | Waiting indefinitely (wait() called) |
THREAD_TIMED_WAITING | Waiting with timeout |
THREAD_TERMINATED | Execution completed |
state transitions
NEW -> start() -> RUNNABLE
RUNNABLE -> synchronized block -> BLOCKED -> acquire lock -> RUNNABLE
RUNNABLE -> wait() -> WAITING -> notify() -> RUNNABLE
RUNNABLE -> sleep() -> TIMED_WAITING -> timeout -> RUNNABLE
RUNNABLE -> run() completes -> TERMINATED
creating threads
with runnable lambda
Thread t = new Thread(() -> {
System.out.println("Running in thread: " + Thread.currentThread().getName());
});
t.start();
t.join(); // Wait for completion
with runnable implementation
class MyTask implements Runnable {
public void run() {
System.out.println("Task executing");
}
}
Thread t = new Thread(new MyTask());
t.start();
thread api
instance methods
| method | description |
|---|---|
start() | Begin thread execution |
join() | Wait for thread to complete |
join(long millis) | Wait with timeout |
isAlive() | Check if thread is still running |
getName() | Get thread name |
setName(String) | Set thread name |
getPriority() | Get thread priority (1-10) |
setPriority(int) | Set thread priority |
interrupt() | Request thread interruption |
isInterrupted() | Check interrupt status |
static methods
| method | description |
|---|---|
Thread.currentThread() | Get reference to current thread |
Thread.sleep(long millis) | Pause current thread |
Thread.yield() | Hint to yield CPU time |
Thread.interrupted() | Check and clear interrupt status |
priority constants
Thread.MIN_PRIORITY // 1
Thread.NORM_PRIORITY // 5 (default)
Thread.MAX_PRIORITY // 10
thread manager
The runtime maintains a global ThreadManager that tracks all threads:
- Linked list of active threads
- Global thread manager lock for thread-safe operations
- Main thread tracking for proper shutdown
monitors and synchronization
Every object in Rava2 can act as a monitor for thread synchronization.
synchronized methods
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
synchronized blocks
public void transfer(Account from, Account to, int amount) {
synchronized (from) {
synchronized (to) {
from.withdraw(amount);
to.deposit(amount);
}
}
}
monitor internals
Each monitor maintains:
| field | description |
|---|---|
owner | Thread holding the lock (or NULL) |
entry_count | Reentrant lock count |
wait_queue | Linked list of waiting threads |
mutex | pthread mutex for atomicity |
cond | pthread condition variable |
reentrant locking
synchronized void outer() {
// entry_count = 1
inner(); // Same thread can re-enter
}
synchronized void inner() {
// entry_count = 2
// ... work ...
} // entry_count = 1
// outer() returns, entry_count = 0, lock released
wait and notify
wait()
synchronized (lock) {
while (!condition) {
lock.wait(); // Releases lock, waits for notify
}
// Condition is now true, lock is held
}
wait(long timeout)
synchronized (lock) {
long deadline = System.currentTimeMillis() + timeout;
while (!condition) {
long remaining = deadline - System.currentTimeMillis();
if (remaining <= 0) break;
lock.wait(remaining);
}
}
notify() vs notifyAll()
| method | behavior |
|---|---|
notify() | Wakes one waiting thread (arbitrary selection) |
notifyAll() | Wakes all waiting threads |
synchronized (lock) {
condition = true;
lock.notifyAll(); // Wake all waiters
}
wait queue implementation
Threads waiting on a monitor are stored in a WaitNode linked list:
- FIFO ordering for fairness
- Nodes track the waiting thread and next pointer
- notify() removes first node, notifyAll() clears the queue
interruption mechanism
interrupt flag
Each thread has an interrupt flag that can be set by other threads:
Thread worker = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
// Do work
}
System.out.println("Interrupted, cleaning up");
});
worker.start();
Thread.sleep(1000);
worker.interrupt(); // Sets interrupt flag
worker.join();
interrupt behavior
| method | behavior |
|---|---|
interrupt() | Sets the interrupt flag |
isInterrupted() | Checks flag without clearing |
Thread.interrupted() | Checks and clears the flag |
daemon threads
Daemon threads run in the background and don't prevent JVM shutdown:
Thread daemon = new Thread(() -> {
while (true) {
// Background task
Thread.sleep(1000);
}
});
daemon.setDaemon(true);
daemon.start();
// Main thread exits, daemon is terminated
thread-local exception handling
Each thread maintains its own exception state:
exceptionfield stores pending exception- Uncaught exceptions propagate to thread termination
- Exception state cleared on new try block entry
producer-consumer pattern
class BlockingQueue {
private ArrayList<Object> items = new ArrayList<>();
private int capacity;
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
public synchronized void put(Object item) {
while (items.size() >= capacity) {
wait();
}
items.add(item);
notifyAll();
}
public synchronized Object take() {
while (items.isEmpty()) {
wait();
}
Object item = items.remove(0);
notifyAll();
return item;
}
}
worker pool example
class WorkerPool {
private Thread[] workers;
private BlockingQueue taskQueue;
public WorkerPool(int numWorkers) {
taskQueue = new BlockingQueue(100);
workers = new Thread[numWorkers];
for (int i = 0; i < numWorkers; i++) {
workers[i] = new Thread(() -> {
while (true) {
Runnable task = (Runnable) taskQueue.take();
task.run();
}
});
workers[i].start();
}
}
public void submit(Runnable task) {
taskQueue.put(task);
}
}
parallel computation example
public class ParallelSum {
public static void main(String[] args) {
int[] data = new int[1000000];
for (int i = 0; i < data.length; i++) {
data[i] = i;
}
int numThreads = 4;
long[] partialSums = new long[numThreads];
Thread[] threads = new Thread[numThreads];
int chunkSize = data.length / numThreads;
for (int t = 0; t < numThreads; t++) {
int threadIndex = t;
int start = t * chunkSize;
int end = (t == numThreads - 1) ? data.length : start + chunkSize;
threads[t] = new Thread(() -> {
long sum = 0;
for (int i = start; i < end; i++) {
sum += data[i];
}
partialSums[threadIndex] = sum;
});
threads[t].start();
}
for (Thread t : threads) {
t.join();
}
long total = 0;
for (long sum : partialSums) {
total += sum;
}
System.out.println("Total: " + total);
}
}
vm mutex and thread safety
Rava2 uses a global VM mutex to ensure thread safety:
- All object allocations acquire the VM lock
- Garbage collection runs under the lock (stop-the-world)
- Native methods can release the lock for blocking operations
pthread integration
Thread implementation maps directly to pthreads:
| Java operation | pthread call |
|---|---|
Thread.start() | pthread_create() |
Thread.join() | pthread_join() |
Thread.sleep() | nanosleep() |
Thread.yield() | sched_yield() |
synchronized | pthread_mutex_lock/unlock() |
wait() | pthread_cond_wait() |
notify() | pthread_cond_signal() |
notifyAll() | pthread_cond_broadcast() |
thread memory management
- Each thread has its own call stack
- Thread stacks are scanned as GC roots
- Thread name memory tracked with
name_allocatedflag - pthread TLS (thread-local storage) handled by suppression file
debugging threads
./rava2 -d program.java # Debug output shows thread operations
make valgrind # Detect race conditions (with --tool=helgrind)
The valgrind.supp file suppresses known false positives from pthread's internal memory management.