A practical deep-dive into Java concurrency, illustrating how race conditions occur during parallel non-atomic modifications and how to successfully mitigate them using internal class serialization vs. client-side explicit ReentrantLock coordination.
Created
May 31, 2026 20:30
-
-
Save ammadkhalid/43d52befde584228697da696d435c420 to your computer and use it in GitHub Desktop.
Java Thread Safe Concurrency
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.util.List; | |
| import java.util.concurrent.locks.Lock; | |
| import java.util.concurrent.locks.ReentrantLock; | |
| interface incrementCounter { | |
| void increment(); | |
| int getCounter(); | |
| } | |
| class TestThread implements Runnable { | |
| final private String message; | |
| final private ThreadSafeCounter sharedValue; | |
| final private int howManyTimes; | |
| public TestThread(String message, ThreadSafeCounter sharedValue, int howManyTime) { | |
| this.message = message; | |
| this.sharedValue = sharedValue; | |
| this.howManyTimes = howManyTime; | |
| } | |
| private void increment() { | |
| for (int i = 0; i < howManyTimes; i++) { | |
| this.sharedValue.increment(); | |
| } | |
| } | |
| @Override | |
| public void run() { | |
| try { | |
| // lock the thread.. | |
| increment(); | |
| Thread.sleep(1000); | |
| } catch (InterruptedException exception) { | |
| System.err.println(exception.getMessage()); | |
| } finally { | |
| // unlock the thread... | |
| System.out.println("Hi! from TestThread " + message + " " + sharedValue + " " + howManyTimes); | |
| } | |
| } | |
| } | |
| class ThreadSafeCounter implements incrementCounter { | |
| private int counter = 0; | |
| final private Lock lock = new ReentrantLock(); | |
| @Override | |
| public void increment() { | |
| lock.lock(); | |
| try { | |
| counter++; | |
| } finally { | |
| lock.unlock(); | |
| } | |
| } | |
| @Override | |
| public int getCounter() { | |
| lock.lock(); | |
| try { | |
| return counter; | |
| } finally { | |
| lock.unlock(); | |
| } | |
| } | |
| } | |
| public class thread { | |
| public static void main(String[] args) { | |
| ThreadSafeCounter sharedCounter = new ThreadSafeCounter(); | |
| TestThread testThreadOne = new TestThread("T1", sharedCounter, 100 * 1000); | |
| TestThread testThreadTwo = new TestThread("T2", sharedCounter, 100 * 1000); | |
| List<Thread> threads = List.of(new Thread(testThreadOne), new Thread(testThreadTwo)); | |
| for(Thread thread: threads) { | |
| thread.start(); | |
| } | |
| // wait for all of them to be finished! | |
| threads.forEach(thread -> { | |
| try { | |
| thread.join(); | |
| } catch (InterruptedException exception) {} | |
| }); | |
| // print final value | |
| System.out.println("Final Shared Counter: " + sharedCounter.getCounter()); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment