简体   繁体   English

2个线程如何同时访问一个同步块?

[英]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 . 我从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. 描述说2个线程可能一个接一个地进入第二个同步块。 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. 这很简单-第一个同步块(S1)使线程等待,直到队列变为非空。 The second synchronized block (S2) makes a single thread take an item from the queue. 第二个同步块(S2)使单个线程从队列中获取一项。

  1. Thread 1 enters S1. 线程1进入S1。
  2. Thread 1 exists S1 -> queue is not empty 线程1存在S1->队列不为空
  3. Thread 2 enters S1 线程2进入S1
  4. Thread 2 exists S1 -> queue is still not empty 线程2存在S1->队列仍然不为空
  5. Thread 1 enters S2 -> takes an item from the queue and it becomes empty 线程1进入S2->从队列中取出一个项目,它变为空
  6. Thread 1 exists S2 线程1存在S2
  7. Thread 2 enters S2 -> attempts to take an element from the queue, but it's empty -> the exception is thrown. 线程2进入S2->尝试从队列中获取元素,但它为空->引发异常。

As you can see, only 1 thread enters a synchronized block as expected, but this does not guarantee proper synchronization. 如您所见,只有1个线程按预期进入了同步块,但这不能保证正确的同步。

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. queue.wait()释放锁定,该锁定将应用于同步块。 In other words, when queue.wait() is reached, other threads are free to enter the synchronized block. 换句话说,当queue.wait()时,其他线程可以自由进入同步块。 Below I include the working example, in which 5 threads enter the same synchronized block at the same time. 下面,我提供了一个工作示例,其中5个线程同时输入相同的同步块。 You can inspect this code to get a feeling how wait () and notiy()/ notifyAll() methods work: 您可以检查以下代码,以了解wait ()和notiy()/ notifyAll()方法如何工作:

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进入S1
T1 exists S1 T1存在S1
T2 wait for T1 to complete from S1 T2等待T1从S1完成
T1 completes and enters S2 T1完成并进入S2
S1 is free for T2 S1对于T2是免费的
T2 enters S1 T2进入S1
In this ways T1 and T2 can be in two different synchronize block at a time. 这样,T1和T2可以同时处于两个不同的同步块中。 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. 程序员应该编写同步块而不是方法,因为它允许两个线程同时在两个单独的块中工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 两个线程如何同时进入同步块? - How could the two threads enter the synchronized block at the same time? 两个线程可以同时访问同步方法吗? - Can two threads access a synchronized method at the same time? 多个线程不能同时进入同步块吗? - Are not multiple threads able to enter a synchronized block at the same time? 线程如何能够访问应该被阻塞的同步块? - How Threads are able to access Synchronized block which are supposed to be block? 我们可以同时从多个线程访问同一个实例的同步方法和非同步方法吗? - Can we Access Synchronized method and an unsynchronized method of same instance from multiple threads at the same time? 同步块/代码Java上的线程访问 - Threads access on Synchronized Block/Code Java 使用线程同时访问 Java 同步块? - Simultaneous access to a Java synchronized block using threads? 如何通过Junit测试两个线程无法同时访问的同步对象? - How to Junit test a synchronized object not accessed by two threads at same time? 如果两个线程使用不同的监视器,是否可以在同一个 object 上执行相同的同步代码块? - Can two threads execute the same synchronized block of code on the same object if they use different monitors? 2个线程同时访问同步函数 - 2 threads accessing at the same time to a synchronized function
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM