简体   繁体   中英

How can 2 threads access a synchronized block at the same time?

Can you describe how in a multithreaded environment, the below code works incorrectly? I took the code from https://www.javacodegeeks.com/2014/11/multithreading-concurrency-interview-questions-answers.html . The description says 2 threads may enter the 2nd synchronized block one after the other. How can this happen? What is the relation by having 2 synchronized blocks?

public Integer getNextInt() {
    Integer retVal = null;
    synchronized (queue) {
        try {
            while (queue.isEmpty()) {
                queue.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    synchronized (queue) {
        retVal = queue.poll();
        if (retVal == null) {
            System.err.println("retVal is null");
            throw new IllegalStateException();
        }
    }
    return retVal;
}

It's pretty simple - the first synchronized block (S1) makes a thread wait until the queue becomes non-empty. The second synchronized block (S2) makes a single thread take an item from the queue.

  1. Thread 1 enters S1.
  2. Thread 1 exists S1 -> queue is not empty
  3. Thread 2 enters S1
  4. Thread 2 exists S1 -> queue is still not empty
  5. Thread 1 enters S2 -> takes an item from the queue and it becomes empty
  6. Thread 1 exists S2
  7. Thread 2 enters S2 -> attempts to take an element from the queue, but it's empty -> the exception is thrown.

As you can see, only 1 thread enters a synchronized block as expected, but this does not guarantee proper synchronization.

The whole point of using a synchronized block is to create a "transaction" around pieces of code that must be executed together; without the chance of another thread coming in "in between".

Your example has two blocks; and it is very well possible that a first thread leaves the first block; but a second thread kicks in before the first thread can enter the second block.

That is all there is to this.

queue.wait() releases the lock, which is applied on synchronized block. In other words, when queue.wait() is reached, other threads are free to enter the synchronized block. Below I include the working example, in which 5 threads enter the same synchronized block at the same time. You can inspect this code to get a feeling how wait () and notiy()/ notifyAll() methods work:

public class Main {
    static Object lock = new Object();
    public static void main(String args[]) throws InterruptedException {

        Runnable r = () -> {
            System.out.println(" ThreadID: " + Thread.currentThread().getId() + " has started");
            synchronizedBlockExecution();
        };

        for (int i = 0; i < 5; i++) {
            Thread t = new Thread(r);
            t.start();
        }

        Thread.sleep(1000);
        System.out.println("------all threads are notifed to stop waiting!---------");
        synchronized (lock) {
            lock.notifyAll();
        }

    }

    public static void synchronizedBlockExecution() {
            System.out.println("Thread: " + Thread.currentThread().getId() + " is entering synchronized block");
            synchronized (lock) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("Thread: " + Thread.currentThread().getId() + " has left synchronized block");
    }
}

T1 enters S1
T1 exists S1
T2 wait for T1 to complete from S1
T1 completes and enters S2
S1 is free for T2
T2 enters S1
In this ways T1 and T2 can be in two different synchronize block at a time. This will improve performance. Programmer should write synchronize block instead of methods as it allows two thread to work in two separate block at a time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM