在Object类中放置wait(),notify()方法的概念

Sun*_*nny 44 java multithreading notify wait

我只是很难有时间去了解背后把概念wait()Object类.为了这个问题,请考虑是否wait()notifyAll()Thread课堂上.

class Reader extends Thread {
    Calculator c;
    public Reader(Calculator calc) {
        c = calc;
    }

    public void run() {
        synchronized(c) {                              //line 9
        try {
            System.out.println("Waiting for calculation...");
            c.wait();
        } catch (InterruptedException e) {}
            System.out.println("Total is: " + c.total);
        }
    }

    public static void main(String [] args) {
        Calculator calculator = new Calculator();
        new Reader(calculator).start();
        new Reader(calculator).start();
        new Reader(calculator).start();
        calculator.start();
    }
}

class Calculator extends Thread {
    int total;
    public void run() {
        synchronized(this) {                     //Line 31
            for(int i=0;i<100;i++) {
                total += i;
            }
             notifyAll();
        }
    } 
}
Run Code Online (Sandbox Code Playgroud)

我的问题是它可能有什么不同?在第9行中,我们获取对象c上的锁定,然后在我们使用等待之前执行等待满足等待条件的等待,我们需要获取对象的锁定因此对于notifyAll我们已经在第31行获取了对象的对象的锁定.

Gra*_*ray 101

我只是很难理解将wait()放在对象类中的概念为了这个问题,请考虑wait()和notifyAll()是否在线程类中

在Java语言中,您wait()在特定的实例上Object- 分配给该对象的监视器是精确的.如果要向正在该特定对象实例上等待的一个线程发送信号,则调用notify()该对象.如果要向正在该对象实例上等待的所有线程发送信号,则使用notifyAll()该对象.

如果wait()notify()是上Thread,而不是那么每个线程就必须知道每一个其他线程的状态.thread1如何知道thread2正在等待访问特定资源?如果thread1需要调用thread2.notify()它将不得不以某种方式找出thread2等待.需要有一些机制让线程注册他们需要的资源或操作,以便其他人可以在东西准备好或可用时发出信号.

在Java中,对象本身是线程之间共享的实体,允许它们相互通信.线程彼此没有特定的知识,它们可以异步运行.他们运行并锁定,等待并通知他们想要访问的对象.他们不了解其他线程,也不需要知道他们的状态.他们不需要知道正在等待资源的是thread2 - 他们只是在资源上通知他们正在等待的任何人(如果有人)将被通知.

在Java中,我们然后使用锁定对象作为线程之间的同步,互斥和通信点.我们在锁定对象上进行同步,以获取对重要代码块的互斥锁访问并同步内存.如果我们等待一些条件改变,我们会等待一个对象 - 一些资源变得可用.如果我们想要唤醒睡眠线程,我们会通知对象.

// locks should be final objects so the object instance we are synchronizing on,
// never changes
private final Object lock = new Object();
...
// ensure that the thread has a mutex lock on some key code
synchronized (lock) {
    ...
    // i need to wait for other threads to finish with some resource
    // this releases the lock and waits on the associated monitor
    lock.wait();
    ...
    // i need to signal another thread that some state has changed and they can
    // awake and continue to run
    lock.notify();
}
Run Code Online (Sandbox Code Playgroud)

程序中可以有任意数量的锁定对象 - 每个锁定对象锁定特定的资源或代码段.您可能有100个锁定对象,只有4个线程.当线程运行程序的各个部分时,它们可以独占访问其中一个锁定对象.同样,他们不必知道其他线程的运行状态.

这允许您根据需要扩展或缩小软件中运行的线程数.您发现4个线程在外部资源上阻塞太多,然后您可以增加数量.推动受攻击的服务器太难,然后减少运行线程的数量.锁定对象确保线程之间的互斥和通信,与运行的线程数量无关.

  • 哇自我解释,但正如你所指出的,我希望详细说明为什么我们从synchronized块中调用.Wait(),因为在等待状态下,它会释放其他人的锁,这使得其他线程可以访问资源. (4认同)

Rou*_*han 39

为了更好地理解为什么wait()和notify()方法属于Object类,我将给你一个真实的例子:假设一个加油站有一个厕所,其钥匙放在服务台.厕所是通过驾驶者的共享资源.为了使用该共享资源,预期用户必须获得上厕所锁的钥匙.用户前往服务台获取钥匙,打开门,从内部锁定并使用设施.

同时,如果第二个潜在用户到达加油站,他发现厕所已锁定,因此无法使用.他去服务台,但钥匙不在那里,因为它掌握在当前用户手中.当前用户完成后,他解锁门并将钥匙返回服务台.他并不打算等待客户.服务台为等待的客户提供钥匙.如果在厕所被锁定时多于一个预期用户出现,他们必须形成一个队列,等待锁的钥匙.每个帖子都不知道谁在厕所里.

显然,在将此类比应用于Java时,Java线程是用户,而厕所是线程希望执行的代码块.Java提供了一种方法来锁定当前使用synchronized关键字执行它的线程的代码,并使其他希望使用它的线程等到第一个线程完成.这些其他线程处于等待状态.Java并不像服务站那样公平,因为没有等待线程的队列.无论他们要求的顺序如何,任何一个等待线程都可以接下来监视器.唯一的保证是所有线程迟早都会使用受监控的代码.

最后你的问题的答案:锁可能是关键对象或服务台.这些都不是线程.

然而,这些是目前决定马桶是锁定还是打开的物体.这些是能够通知浴室打开("通知")或要求人们等待锁定等待的对象.

  • 世界上的人就像一条线,他们使用共享资源,比如火车站候车厅、加油站等。所有这些人都不知道谁在等待他们获取和释放资源。是资源宣布他们是免费和可用的,而不是人,这就是为什么对象类有 wait() 和 notify() 方法。 (2认同)

Rav*_*abu 7

简单来说,原因如下。

  1. Object 有显示器。
  2. 多个线程可以访问一个Object. 一次只有一个线程可以为synchronized方法/块持有对象监视器。
  3. wait(), notify() and notifyAll()Object类中的方法允许在该类上创建的所有线程object与其他线程进行通信
  4. 锁定(使用synchronized or LockAPI)和通信(wait() and notify())是两个不同的概念。

如果Thread类包含wait(), notify() and notifyAll()方法,那么它将产生以下问题:

  1. Thread 沟通问题
  2. Synchronization在对象上是不可能的。如果每个线程都有监视器,我们就没有办法实现同步
  3. Inconsistency 在对象状态

有关更多详细信息,请参阅本文


Ale*_*x D 6

这个问题的其他答案都错过了关键点,在Java中,每个对象都有一个互斥锁.(我假设您知道互斥锁或"锁定"是什么.)在大多数具有"锁定"概念的编程语言中并非如此.例如,在Ruby中,您必须根据需要显式创建任意数量的Mutex对象.

我想我知道为什么Java的创造者做出了这个选择(虽然,在我看来,这是一个错误).原因与包含synchronized关键字有关.我相信Java的创造者(天真地)认为通过synchronized在语言中包含方法,人们可以很容易地编写正确的多线程代码 - 只需将所有共享状态封装在对象中,声明访问该状态的方法synchronized,你完成了!但它并没有那么成功......

无论如何,因为任何类都可以有synchronized方法,每个对象需要一个互斥锁,synchronized方法可以锁定和解锁.

wait并且notify都依赖于互斥体.也许你已经明白为什么会出现这种情况......如果不是我可以添加更多解释,但是现在,让我们说两种方法都需要在互斥锁上工作.每个Java对象都有一个互斥体,因此它是有道理的,wait并且notify可以在任何Java对象上调用.这意味着他们需要被声明为方法Object.

另一个选择是将静态方法放在Thread什么上,或者将其Object作为参数.对于新的Java程序员来说,这可能会少得多.但他们并没有这样做.改变任何这些决定都为时已晚; 太糟糕了!

  • 好的,注意到,包含该点的+1.确实,后来的JRE版本包含显式锁对象,但从第一天开始,隐式互斥锁就在那里,这就是为什么`wait`和`notify`是`Object`的方法.如果原始JRE中包含显式锁定对象或更好的条件队列对象,那么"wait"和"notify"肯定会与它们相关联. (2认同)