============================================================ IT6003 - Advanced Java Programming Lab Session 4: Multithreading & Concurrency State University of Zanzibar (SUZA) ============================================================ OBJECTIVES: - Create threads using Thread class and Runnable interface - Understand thread lifecycle and synchronization - Use wait/notify for inter-thread communication - Apply java.util.concurrent utilities ============================================================ PART A: Thread Basics [30 minutes] ============================================================ Exercise 1: Creating Threads ------------------------------ a) Create a class Printer extends Thread that prints "Thread: [name] - count: [i]" for i = 1 to 10, with Thread.sleep(200) between each print. b) Create a class Counter implements Runnable that counts from 1 to 10. c) In main(), create 3 Printer threads and 2 Counter threads. d) Start all threads and observe interleaved output. e) Use thread.setName() to give meaningful names. Exercise 2: Thread Methods ----------------------------- a) Create two threads. Use join() on the first so main waits for it. b) Set one thread as daemon using setDaemon(true). Observe behavior when main exits. c) Use Thread.sleep(1000) to pause a thread for 1 second. d) Print thread states using getState(): NEW, RUNNABLE, BLOCKED, WAITING, TERMINATED. e) Set different priorities with setPriority(). Print them. Exercise 3: Race Condition Demo ---------------------------------- a) Create a shared Counter class with int count and methods increment() and getCount(). b) Create 10 threads, each calling increment() 10000 times. c) After all finish (use join), print count. Expected: 100000. d) Run several times. Observe count is often LESS than 100000. e) Explain in comments why this happens (race condition). ============================================================ PART B: Synchronization [30 minutes] ============================================================ Exercise 4: Synchronized Methods ----------------------------------- a) Copy Exercise 3's Counter but add synchronized to increment(). b) Run the same test. Verify count is always 100000. c) Create a synchronized getCount() method. d) Measure execution time with and without synchronization. Exercise 5: Synchronized Block --------------------------------- a) Create a BankAccount class with double balance. b) Implement deposit(double) and withdraw(double) with synchronized blocks. c) Create 5 deposit threads (+100 each, 50 times) and 5 withdraw threads (-50 each, 50 times). d) Start all threads, join all, print final balance. e) Expected: initial + (5*50*100) - (5*50*50) = initial + 12500. Exercise 6: Deadlock Demonstration ------------------------------------- a) Create two Object locks: lock1 and lock2. b) Thread A: synchronized(lock1) { sleep(100); synchronized(lock2) { ... } } c) Thread B: synchronized(lock2) { sleep(100); synchronized(lock1) { ... } } d) Run and observe the deadlock (program hangs). e) Fix by acquiring locks in the same order in both threads. ============================================================ PART C: Inter-Thread Communication [30 minutes] ============================================================ Exercise 7: Wait/Notify -------------------------- a) Create a SharedBuffer class with a single int value and boolean available. b) produce(int val): if available, wait(). Set value, available=true, notify(). c) consume(): if not available, wait(). Get value, available=false, notify(). d) Create Producer thread producing values 1-10. e) Create Consumer thread consuming and printing values. f) Verify all values are consumed in order. Exercise 8: Producer-Consumer with Buffer -------------------------------------------- a) Create SharedQueue with LinkedList and capacity 5. b) produce(): if queue full, wait(). Add item, notifyAll(). c) consume(): if queue empty, wait(). Remove item, notifyAll(). d) Create 2 producers (each producing 10 items) and 1 consumer. e) Print each produce/consume action with thread name. f) Re-implement using ArrayBlockingQueue (compare code simplicity). ============================================================ PART D: java.util.concurrent [30 minutes] ============================================================ Exercise 9: ExecutorService ------------------------------ a) Create a FixedThreadPool with 3 threads. b) Submit 10 Runnable tasks that print task number and thread name. c) Observe that only 3 threads handle all 10 tasks. d) Use Callable to return results from tasks. e) Collect Future objects and print results. f) Shutdown the executor properly with shutdown() and awaitTermination(). Exercise 10: Concurrent Collections --------------------------------------- a) Create ConcurrentHashMap for concurrent word counting. b) Create 5 threads, each counting words from a different text segment. c) Use merge() or compute() for thread-safe updates. d) Compare with a regular HashMap (may produce incorrect results). Exercise 11: AtomicInteger ----------------------------- a) Replace the synchronized counter from Exercise 4 with AtomicInteger. b) Use incrementAndGet() in 10 threads (10000 increments each). c) Verify result is always 100000 without synchronized keyword. d) Measure performance vs synchronized. Print comparison. Exercise 12: CountDownLatch Race Simulation --------------------------------------------- a) Create 5 "runner" threads. b) Each runner prepares (random sleep 1-3 seconds) then calls latch.countDown(). c) Main thread calls latch.await() to wait for all runners to prepare. d) After all ready, main prints "GO!" and all runners start racing. e) Each runner takes random time (1-5 seconds) to finish. f) Print finish order with times. ============================================================ SUBMISSION: Submit all .java files in a folder named Lab04_RegNo/ ============================================================