龙空技术网

Java的锁定、同步和线程间通信问题

码农世界 119

前言:

目前看官们对“系统java 停用”大致比较重视,你们都需要了解一些“系统java 停用”的相关文章。那么小编同时在网摘上汇集了一些关于“系统java 停用””的相关文章,希望姐妹们能喜欢,你们一起来了解一下吧!

以下是我列出的一些关于锁定、同步、线程间通信以及 Java 中的等待、通知和通知所有方法的最佳问题。这些问题实际上是在几次Java面试中提出的,如果你有几年的Java经验,那么你可以毫无困难地回答它们。

1. 什么时候需要在 Java 中同步?

首先,作为一名Java程序员,你应该知道你的代码什么时候需要同步。答案就在Brian Goetz创造的“同步座右铭”中,它说:“如果你写了一个变量,下一个可能被另一个线程读取,或者你正在读取一个变量,这个变量可能是另一个线程最后写入的,你必须使用同步”。

假设您有以下代码:现在,这个 closed 是一个布尔字段,当用户按下一个按钮并由运行此循环的另一个线程读取时,可以由一个线程设置。在这种情况下,您需要某种同步,以便一个线程所做的更改对其他线程可见。

您可以通过在 Java 中使用同步关键字或易失性关键字来实现该同步。事实上,这是使用易失性字段的正确情况,它提供了低成本的同步。

现在,在某些情况下,即使多个线程执行代码,但您不需要任何同步,例如,一旦安全初始化,就从 HashMap 读取。读取值是一种安全操作,无需同步即可完成。前提是您正在读取的值在像最终变量一样初始化后不会更改。

所以,不要在面试中说,如果一个代码是由多个线程执行的,那么你需要同步,你还需要考虑代码在做什么。如果一个线程正在读取而另一个线程正在写入,那么您肯定需要某种同步来实现您想要的输出。

while(!closed){  printf("Yes, losing weigth is possible");}
2. 在 Java 中何时使用等待和通知方法?

wait()、notify() 和 notifyAll() 方法是 Java 中线程间通信的工具。另一组类似的工具是Java 5中的await(),signal()和signalAll(),它们适用于Lock和Condition对象。

当您的程序有多个线程并且它们需要相互通信时,您需要此工具。最好的例子是生产者-消费者问题,其中两个线程需要就其操作相互通信,因为这可能会影响其他线程。

例如,如果共享队列为空,并且使用者正在等待队列中的项目(您可以使用 java 5 中的 wait() 方法或 condition.await() 使线程等待条件),则生产者可以在成功插入后通知消费者。一旦使用者收到该通知,他就可以重新开始工作。您可以进一步查看这些 Java 多线程课程,以了解有关 Java 中同步的更多信息。

而且,如果您想了解更多信息,可以在此处查看有关如何在 Java 中使用等待和通知解决生产者-消费者问题的更多信息。

3. 在 Java 中通知和通知所有有什么区别?

在回答这个问题之前,我给你一般的建议,经常注意名字,往往它揭示了目的。顾名思义,notify() 方法仅将通知发送到等待条件的众多线程之一,而 notifyAll() 将通知发送给所有线程。

现在,在 notify() 的情况下,哪个线程将收到通知?好吧,选择一个随机线程。这也是棘手的多线程问题之一,您可能会得到很多后续问题,因此请确保您正确回答,正如您将在下一个问题中看到的那样。

4. 为什么使用 notifyAll 比通知方法更安全?

如果由于某种原因,从 notify() 方法接收通知的随机线程无法继续并再次开始等待,那么您的程序将不会进一步进行。如果调用 notify() 的线程在发送通知后进入等待状态,则应用程序可能会导致完全死锁,因为这样就没有活动线程通知所有等待线程。

这就是为什么 notifyAll() 是比 notify() 更安全的选项,因为它会向所有线程发送通知。如果无法继续,则还有更多线程可以完成这项工作。请参阅此处以了解有关 Java 中通知和通知所有方法之间区别的更多信息。

5. 在 Java 的多线程环境中,这段代码有什么问题?

if(account.getBallance() >= withdrawl ){  double ballance = account.getBallance() - withdrawl;  account.setBallance(ballance);}

这段代码的灵感来自Cay S. Horstmann在Core Java Volume 1中给出的银行示例,这是学习Java的最佳书籍之一。这是应该一起发生的非原子操作的常见情况。

如果多个线程执行此代码,则一个线程可能在测试帐户中有足够的余额等条件后被停用,但是当它启动并重新启动时,情况可能已被另一个线程通过处理另一个提款操作而改变,现在没有足够的资金来完成此交易。

为了使此代码线程安全且正确,您必须将测试和事务包装在一个同步块中,如下所示:

如果您使用的是 Java 5 并且知道如何使用 java.util.concurrent.lock.Lock 接口,那么您也可以使用 ReentrantLock 来保护此代码。这也称为关键部分,即一次只能由一个线程执行的代码段。

// member variable in classObject accountLock = new Object();sychronized(accountLock){ if(account.getBallance() > withdrawl ){  double ballance = account.getBallance() - withdrawl;  account.setBallance(ballance); }}

6. 线程可以在不获取锁定 Java 的情况下进入同步块吗?

不,这是不可能的。线程在进入之前必须获取同步块所需的锁。sync关键字在线程进入和释放锁线程离开块时获取锁。由于只能有一个锁,并且如果它被另一个线程使用,那么这个线程需要等到锁可用。

现在可能有很多陷阱,有时Java程序员使用不同的锁来保护相同的资源,这是完全错误的。这就像浴室里的两扇门,有单独的锁和钥匙。你不想让别人看到你在厕所里,对吧?

因此,您必须使用相同的锁对象或互斥锁来保护相同的资源,如果您必须使用多个锁,请使用多级锁,即您打开房屋门然后打开厕所门,因此您需要房屋和厕所钥匙才能使用厕所。

7. 调用wait()方法后线程会发生什么?它回锁吗?

这是关于这个话题最有趣的问题之一。我见过很多程序员在面试中被问到时感到困惑,为什么当调用wait()后第一个线程卡住时,另一个线程被锁定了?

好吧,当线程看到进一步继续的条件不行时,它决定通过调用wait()方法等待,但它确实释放了锁。是的,这非常重要,线程没有进一步进行,但锁被释放,以便等待锁的其他线程可以继续。

这也是 sleep() 和 wait() 方法之间的主要区别,后者用于暂停线程(见这里))

8. 一旦另一个线程调用 notifyAll() 后,等待线程(调用了 wait() 方法)会发生什么?

当线程调用 notifyAll() 或 signalAll() 方法时,所有等待该条件的线程(与 lock 和 notifyAll() 关联的条件在持有锁的对象上调用)都会收到通知。

现在,它们无需等待状态,但仍需要线程调度程序分配 CPU 才能继续。当他们得到机会时,他们会继续前进。请参阅此处以了解有关 Java 中的等待、通知和通知所有方法的更多信息。

9. 线程等待锁定和调用wait()方法后等待有什么区别?

一旦锁定空闲并被此锁获取并且 CPU 分配给它,等待锁定的线程就会被激活(有资格再次运行)。即使锁是空闲的,等待条件的线程也可能无法再次运行,但他没有收到来自另一个线程的任何通知,例如,直到有人调用 notify() 或 notifyAll() 在 wait() 的情况下和 signal() 或 signalAll () 在等待条件对象的情况下。

10. 为什么你应该检查 while 循环而不是 if 块的等待条件?

有趣而实用的问题之一。您需要检查循环中的等待条件,因为即使在 notify() 唤醒调用后,等待条件可能仍然有效。如果线程在唤醒后未检查等待条件,则继续操作可能会造成伤害。

这可能是由于多种原因造成的,例如,多个线程在该条件下等待,直到第二个线程有机会,第一个线程已经继续进行并使该唤醒调用无效。

例如,如果 3 个使用者正在等待,生产者将一个项目放入队列并通知所有三个项目,则第一个使用者将获得该项目,而其他两个消费者需要等待。这只有在检查 while() 循环中的条件时才有可能。

顺便说一句,这也是使用 wait() 和 notify() 的标准习语,正如 Joshua Bloch 在 Effective Java 中建议的那样。

12. 为什么在java.lang.Object类而不是Thread中定义了等待和通知方法?

简短的回答是因为 Object 在 Java 中也是一个监视器。它带有一个关联的锁,wait()、notify()与等待锁定条件相关联,因此在java.lang.Object中定义它们是有意义的。有关长答案,请参阅本文。

这就是关于wait()和notify(),锁定,同步和线程间通信的一些Java面试问题。我知道,这是难以理解和掌握的概念之一,这就是为什么我问了一些棘手的问题。一旦你习惯回答这个问题,你对wait()和notify()的理解就会变得坚实。

继续编写代码并思考如果同一代码块由多个线程同时运行会发生什么。请记住,Thread 可以在任何一行停止,唯一的代码行可以由多个指令组成,例如++或!=不是原子的。

我还建议从头到尾至少阅读一次Java 并发实践。它将帮助您填补 Java 中现有多线程、同步和并发知识的空白。

标签: #系统java 停用