有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何使两个线程不能同时执行方法。在代码内部发生了什么。

我有一个在某个类中定义的同步方法

我们知道,如果我们创建一个同步的方法,那么一次只能有一个线程执行该任务

这个方法内部发生了什么

其他线程如何不能执行相同的任务来运行相同的方法

据我所知,join应用于该特定线程。但是管道中的第二个线程如何知道第一个线程已经完成了任务

告诉我我是否正确


共 (4) 个答案

  1. # 1 楼答案

    在Java语言中,每个对象都有一个监视器,它基本上是一个锁

    此锁为对象方法(如wait/signal/signalAll)提供动力,这些方法在每个对象上都可用

    使用synchronized关键字时,幕后发生的事情是编译器编写获取监视器(锁)的代码,并在调用完成时释放它

    如果方法是静态的,则访问的监视器是类对象的监视器

    您可以在此处阅读有关此关键字的更多信息: http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

  2. # 2 楼答案

    We know that if we create a method as synchronized, then only one thread is able to execute the task at a time.

    不是真的!两个或多个线程可以同时进入相同的synchronized块。而且,这不仅仅是理论上的:它经常发生在精心设计的程序中

    以下是两个或多个线程可以而不是做的事情:两个或多个线程不能同时在同一对象上同步。如果您希望确保一次只有一个线程可以输入特定的方法(但为什么?†),那么您需要编写该方法,以便对该方法的所有调用将在同一对象上同步。如果是静态方法,这很容易做到,因为:

    class Foobar {
        synchronized MyType baz() { ... }
    }
    

    表示与此相同:

    class Foobar {
        MyType baz () {
            synchronized (Foobar.class) { ... }
        }
    }
    

    静态同步方法的所有调用在拥有该方法的类对象上同步

    [what prevents two threads from synchronizing on the same object at the same time]?

    操作系统。任何想要用于实际工作的JVM都使用本机线程来实现Java线程。本机线程是通过调用操作系统来创建和管理的线程。特别是,它是被称为调度程序的操作系统的一部分。我不打算详细介绍操作系统调度程序的工作原理——有很多关于这个主题的书——但它的工作是决定哪些线程可以运行,何时运行,在什么处理器上运行

    典型的调度程序使用队列跟踪所有未实际运行的线程。一个特殊队列运行队列,包含准备运行但等待CPU运行的线程。运行队列上的线程称为runnable。任何其他队列上的线程都被阻塞(即,不允许运行),直到发生导致调度程序将其放回运行队列的事件

    与Java监视器(参见@TheLostMind的答案)相对应的操作系统对象通常称为互斥体。对于每个互斥体,都有一个阻塞的线程队列,等待进入它。本机线程通过调用操作系统进入互斥锁。这使操作系统有机会暂停线程,并在互斥体中已有其他线程时将其添加到互斥体的队列中。当线程离开互斥锁时,这也是一个系统调用;它使调度器有机会从互斥体的队列中选择一个线程,并将其放回运行队列

    就像我说的,调度器如何做这些事情的细节在这里谈得太深了。谷歌是你的朋友


    †不要担心哪些线程可以同时进入哪个方法。相反,要担心哪些线程会接触哪些数据。同步的目的是允许一个线程临时将数据置于不希望其他线程看到的状态

  3. # 3 楼答案

    一个线程(首先)获取对象的锁,另一个线程等待获取该对象的锁

    任务完成后,第一个线程使用notify()notifyAll()方法向等待的线程发送通知

  4. # 4 楼答案

    此方法内部发生了什么

    当您说一个(实例级)方法是同步的时,线程必须首先获得对象上的锁(即,首先持有该对象的监视器)才能访问它。只要一个线程持有/监视器,其他线程就无法访问它。因为他们无法锁定对象(就像对象的门)

    其他线程如何不能执行相同的任务来运行相同的方法

    因为只要一个线程仍然持有监视器,其他线程就会等待。i、 例如,他们不能自己访问监视器。因此,它们被阻止并将在该对象的等待集/队列中等待

    联接应用于该特定线程。但是管道中的第二个线程如何知道第一个线程已经完成了任务

    Join()确保在另一个线程上调用Join()的线程等待第二个线程完成其执行

    注意:调用join时,在两个线程之间建立关系之前会发生。因此,在调用join或从join返回之前发生的任何都对其他线程始终可见

    编辑:

    Assume ThreadA and ThreadB are two threads running concurrently.
    
    ThreadA
    {
     run(){
     //some statements;
      x=10; // assume x to be some shared variable
     ThreadB.join();
    // here ThreadA sees the value of "x" as 20. The same applies to synchronized blocks.
    // Suppose ThreadA is executing in a Synchronized block of Object A, then after ThreadA //exits the synchronized block, then other threads will "always" see the changes made by //ThreadA
    // some other statements
    }
    }
    
    ThreadB{
    run(){
    //some statements
     x=20;
    }
    

    检查:Happens Before