Understanding Java Multithreading Concurrency and Synchronization

This article explains Java multithreading concurrency issues, demonstrates how synchronized methods, synchronized blocks, static synchronization, mutex locks, deadlocks, and the differences between wait() and sleep() work, and provides runnable code examples to illustrate each concept.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Understanding Java Multithreading Concurrency and Synchronization

When multiple threads operate on the same data concurrently, the unpredictable execution order can cause data corruption or system failure; this is the core concurrency safety problem in Java.

1. Synchronized Methods – Declaring a method with synchronized makes it a synchronized method, ensuring that only one thread can execute its body at a time. The article includes a bean‑grabbing example ( public class SyncDemo { ... }) that throws an exception when the bean count reaches zero, demonstrating how synchronization prevents negative values.

public class SyncDemo {
    public static void main(String[] args) {
        Table table = new Table();
        Thread t1 = new Thread(){
            public void run(){
                while(true){
                    int n = table.getBean();
                    Thread.yield();
                    System.out.println(Thread.currentThread().getName()+",豆豆还剩"+n);
                }
            }
        };
        Thread t2 = new Thread(){
            public void run(){
                while(true){
                    int n = table.getBean();
                    Thread.yield();
                    System.out.println(Thread.currentThread().getName()+",豆豆还剩"+n);
                }
            }
        };
        t1.start();
        t2.start();
    }
}

class Table {
    private int bean = 10;
    public synchronized int getBean(){
        if(bean == 0){
            throw new RuntimeException("没有豆豆了");
        }
        Thread.yield(); // simulate context switch
        return bean--;
    }
}

2. Synchronized Blocks – By limiting the synchronized region to a specific code block, you can improve efficiency while still guaranteeing thread safety. The article shows a shopping‑mall simulation where only the “try‑on‑clothes” section is synchronized.

synchronized(同步监视器){
    // code that needs to run atomically
}

Example:

public class Syncdemo2 {
    public static void main(String[] args) {
        Shop shop = new Shop();
        Thread t1 = new Thread(){
            public void run(){ shop.buy(); }
        };
        Thread t2 = new Thread(){
            public void run(){ shop.buy(); }
        };
        t1.start();
        t2.start();
    }
}

class Shop {
    public void buy(){
        try {
            String name = Thread.currentThread().getName();
            System.out.println(name+"选衣服");
            Thread.sleep(2000);
            synchronized(this){
                System.out.println(name+"试衣服");
                Thread.sleep(2000);
            }
            System.out.println(name+"结账走人");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3. Static Synchronized Methods – When a static method is marked synchronized, the lock is on the Class object, ensuring that only one thread can execute any static synchronized method of that class at a time.

public class Syncdemo3 {
    public static void main(String[] args) {
        Thread t1 = new Thread(){ public void run(){ Foo.dosome(); } };
        Thread t2 = new Thread(){ public void run(){ Foo.dosome(); } };
        t1.start();
        t2.start();
    }
}

class Foo {
    public synchronized static void dosome(){
        try {
            String name = Thread.currentThread().getName();
            System.out.println(name+"正在运行dosome方法");
            Thread.sleep(3000);
            System.out.println(name+"运行结束》》");
        } catch (Exception e) { e.printStackTrace(); }
    }
}

4. Mutex Locks – Multiple synchronized methods that lock on the same object act as a mutual exclusion lock; only one thread can hold the lock at a time.

public class Syncdemo4 {
    public static void main(String[] args) {
        Eoo eoo = new Eoo();
        Thread t1 = new Thread(){ public void run(){ eoo.test01(); } };
        Thread t2 = new Thread(){ public void run(){ eoo.test02(); } };
        t1.start();
        t2.start();
    }
}

class Eoo {
    public synchronized void test01(){
        String name = Thread.currentThread().getName();
        System.out.println(name+"正在运行1方法");
        Thread.sleep(3000);
        System.out.println(name+"1运行完毕");
    }
    public synchronized void test02(){
        String name = Thread.currentThread().getName();
        System.out.println(name+"正在运行2方法");
        Thread.sleep(3000);
        System.out.println(name+"2运行完毕");
    }
}

5. Deadlock – When two threads each hold a lock that the other needs, they wait indefinitely, causing a deadlock. The article provides a classic example with two objects A and B locked in opposite order.

public class Syncdemo5 {
    public static void main(String[] args) {
        Poo p = new Poo();
        Thread t1 = new Thread(){ public void run(){ p.method1(); } };
        Thread t2 = new Thread(){ public void run(){ p.method2(); } };
        t1.start();
        t2.start();
    }
}

class Poo {
    Object A = new Object();
    Object B = new Object();
    public void method1(){
        synchronized(A){
            // ...
            method2(); // tries to lock B while holding A
        }
    }
    public void method2(){
        synchronized(B){
            // ...
            method1(); // tries to lock A while holding B
        }
    }
}

6. Difference Between wait() and sleep() – wait() is defined in Object, releases the monitor and must be called inside a synchronized block, while sleep() is a static method of Thread, does not release the lock, and can be called anywhere (but requires handling InterruptedException). The article demonstrates this with two threads where one uses wait() on a shared StringBuilder and the other uses notify() to wake it.

public class WaitDemo {
    public static void main(String[] args) {
        Thread t1 = new ThreadMy01();
        Thread t2 = new ThreadMy02();
        t1.start();
        t2.start();
    }
}

class ThreadMy01 extends Thread {
    static StringBuilder str = new StringBuilder();
    public void run(){
        synchronized(str){
            for(int i=0;i<5;i++){
                str.wait(300); // releases lock
                str.append('a');
                System.out.println(Thread.currentThread().getName()+str);
            }
        }
    }
}

class ThreadMy02 extends Thread {
    public void run(){
        synchronized(ThreadMy01.str){
            for(int i=0;i<2;i++){
                Thread.sleep(2000);
                System.out.println("888");
            }
            ThreadMy01.str.notify(); // wakes waiting thread
        }
    }
}

The article concludes with a diagram of the Java thread lifecycle and encourages readers to explore further interview questions and resources.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

thread safetymultithreading
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.