Java Assignment- 7
Multithreading & Concurrency
Basic Questions
- In simple words, explain what multithreading is in Java and mention two real-life use cases where multiple threads are helpful.
- List the main thread states in Java (NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED) and describe in one short line what each means.
- Write a small program that extends Thread, starts a thread that prints “Hello from Thread” five times, and then joins it in main.
- Write a small program that implements Runnable, starts a thread that prints numbers 1 to 5, and then waits for it to finish.
- Write two methods—one that calls t.run() directly and another that calls t.start()—using the same Thread object. Print the current thread’s name inside the task to show the difference.
- Create two threads that both print their own names 5 times. Start both, and show interleaved output on the console.
- Write a program that uses Thread.sleep(500) inside a loop and prints the current time on each step.
- Write a program that sets the name of a thread to “Worker-1” and prints the name from inside run().
- Create a shared counter variable in main, and in one thread increase it 100 times without synchronization. Print the final value and explain (in a comment) why the result may not be 100.
- Rewrite the previous question to use the synchronized keyword on a method that increments the counter. Show that the final value becomes correct.
- Create two threads, one that prints even numbers from 2 to 10 and another that prints odd numbers from 1 to 9. Start both and show the combined output.
- Write a small program that demonstrates Thread.yield() by calling it inside a loop and printing a message each time.
- Write a program that sets the priority of two threads (MIN_PRIORITY and MAX_PRIORITY) and prints their priorities. Note in a comment that priorities are hints and may not guarantee order.
- Create a ThreadGroup named “MyGroup”, start two threads in that group, and print the active thread count of the group.
- Explain in 2–3 lines the difference between Runnable and Callable.
- Write a small example that uses Timer and TimerTask to print “Tick” once after 1 second (single-shot).
- Use an AtomicInteger to increment a counter from multiple threads (two threads, 100 increments each) and print the final result.
- Read a line from the console in main, start a thread that prints the reverse of the string, and join the thread before exiting.
- Write a simple example that catches and prints InterruptedException when a sleeping thread is interrupted.
- Write a small multithreaded program that starts two worker threads and waits for both to finish using join(), then prints “All done”.
Intermediate Questions
- Write a producer–consumer demo with one producer thread that adds numbers 1 to 5 into a shared object and one consumer thread that removes and prints them. Use wait() and notify() in a simple synchronized buffer of size 1.
- Create two threads that try to call withdraw(10) on a shared bank account 100 times each. First write it without synchronization and show a wrong final balance, then add synchronized to fix it.
- Write a small program that deliberately creates a deadlock using two locks lockA and lockB. Then write a second version that prevents deadlock by always locking in the same order.
- Use a ThreadGroup to start three threads that each print their name and sleep for 200 ms. Print the group’s active count before and after all threads finish.
- Create a class that implements Callable<Integer> returning the sum of numbers 1…100. Submit it to an ExecutorService and get the result using Future.get().
- Write a TimerTask that prints the current time every second, and cancel the timer after 5 prints.
- Use AtomicInteger to implement a thread-safe sequence generator with a nextId() method. Start three threads and have each request 3 IDs; print all IDs.
- Use Java 8 parallel stream to compute the sum of squares for numbers 1…1,000,000 and print the result. Then do the same with a normal stream and print both times.
- Write a task that processes an array of 10 integers in parallel using ForkJoinPool with a simple RecursiveTask<Integer> that sums a range (split when size > 2). Print the final sum.
- Create a small shared message object with String text. One thread sets the text and calls notifyAll(). Two waiting threads print the text when notified. Use wait() and notifyAll() correctly.
- Show how to handle InterruptedException properly in a loop: when interrupted, restore the interrupt status using Thread.currentThread().interrupt() and break the loop.
- Write a method that starts a thread, lets it run for 2 seconds, then interrupts it. Inside the thread, catch the interrupt while sleeping and print a friendly message.
- Explain in comments and code the difference between synchronized method and synchronized block using a small counter example.
- Demonstrate a simple read–compute–write pipeline using three threads and a shared array: one fills values, one doubles each value, one prints them. Use join() between stages (no wait/notify required).
- Show the difference between Runnable (no return) and Callable (returns value) by running one of each in an ExecutorService and printing the Callable result.
- Use a concurrent collection by choosing ConcurrentHashMap<Integer, String>. Start two threads that put different key–value pairs and then print the map size at the end.
- Use CopyOnWriteArrayList<String> to add elements from two threads and then iterate safely from the main thread while modifications continue.
- Write a small utility that runs 5 Runnable tasks using a fixed thread pool of size 2 (Executors.newFixedThreadPool(2)), prints the current thread name in each task, and then shuts down the pool.
- Create two threads that alternate printing “Ping” and “Pong” ten times total. Use a shared lock and wait()/notify() to alternate correctly.
- Write a method that measures and prints the time difference between running 4 CPU-bound tasks sequentially and running them in parallel using an ExecutorService.
Advanced Questions
- Implement a bounded buffer of size 3 using wait()/notifyAll(). One producer produces 10 integers; two consumers remove and print them. Ensure no lost or duplicated data.
- Build a deadlock-free transfer between two bank accounts by using a lock ordering rule based on object identity (or account ID). Show that concurrent transfers never deadlock.
- Implement a timed wait with wait(timeout) in a request/response scenario: a requester thread waits up to 2 seconds for a reply; another thread sets the reply. Print whether a timeout happened or a reply arrived.
- Write a ForkJoin task MaxFinder that finds the maximum in a large int[]. Split when the segment length is over a threshold, combine results, and print the max.
- Write a small scheduler using Timer that runs a cleanup task every 2 seconds and a reporting task every 3 seconds; stop both after 10 seconds. Show clean shutdown.
- Implement a thread-safe rate limiter using an AtomicInteger that allows at most N operations per second. Use a Timer or a scheduled task to reset the counter each second. Demonstrate with multiple threads.
- Using parallel streams, compute word counts from a large String[] (split on whitespace), then sort results and print the top 5 words. Compare time with a normal stream.
- Implement a work-stealing style split using ForkJoinPool to count how many numbers in a large array are prime. Use a simple prime check and combine partial counts.
- Write a robust worker that loops, does work in chunks, and checks Thread.interrupted() regularly. When interrupted, it saves progress to a file and exits cleanly. Show an interrupt from main after a short delay.
- Write a complete multithreaded program that:
- Reads file names from a directory,
- Uses a thread pool to count lines in each file in parallel,
- Uses a concurrent collection to store file → lineCount,
- Handles InterruptedException and I/O errors cleanly,
- Prints a final summary map and total line count.