我在网上搜索一个生产者和消费者的问题,我得到了这个链接。程序员在这里使用了sharedqueue
的向量。
我想为什么我需要一个同步块,因为Vector已经是线程安全的了。它必须自己处理线程。
但当我试图移除同步块时。它给我一个IllegalMonitorStateException
。下面是Product方法的代码段
private void produce(int i) throws InterruptedException {
//wait if queue is full
while (sharedQueue.size() == SIZE) {
// synchronized (sharedQueue) {
System.out.println("Queue is full " + Thread.currentThread().getName()
+ " is waiting , size: " + sharedQueue.size());
sharedQueue.wait();
// }
}
//producing element and notify consumers
// synchronized (sharedQueue) {
sharedQueue.add(i);
sharedQueue.notifyAll();
// }
}
我的问题是为什么我们需要同步或锁定一个已经是线程安全的对象?
如果没有同步,则可以使用以下内容:
Producer Thread Consumer Thread
if (sharedQueue.isEmpty) {
sharedQueue.add(i);
sharedQueue.notifyAll();
sharedQueue.wait()
}
因此,即使队列中有数据,使用者线程也可能永远等待,因为在它测试数据和开始等待有关添加数据的通知之间添加了东西。
当然也有解决方法,比如wait
上的超时,但这些方法都有轮询开销、轮询间隔引起的延迟、难看的代码等等。当您可以仅仅使用同步时,没有理由诉诸这些东西。
那么为什么queue类是线程安全的还不够呢?好吧,线程安全类不是魔术!线程安全仅仅意味着,对该类实例的单个方法调用是线程安全的。例如,如果两个线程同时对同一个实例执行add
操作,它不会破坏任何内容,也不会用另一个操作擦除一个操作,或类似的操作。
但是如果您有多个线程执行多个操作,那么它们可以交错,这就是多线程和先发制人的多任务处理的全部意义!交错操作会发生什么,这取决于操作。例如,许多执行add
操作的线程会按照未指定的顺序添加内容,但这可能是可以的。但当您不希望操作以“随机”顺序发生时,就需要使用同步。
如上面示例所示,在这种情况下,即使在队列中有数据,“随机”顺序也会导致消费者无限期地等待。事实上,如果您有序列“做修改,通知服务员”,而服务员做“看看是否有什么事情要做,否则等待”,您就会遇到同样的问题,并且必须在修改-通知和检查-等待周围使用同步。
你会得到错误,因为Java要求你在通知的时候有锁,因为上面解释过,没有锁是没有意义的,它总是一个错误,一个bug。这不是Java特有的,这是这类机制的基础,它们总是需要锁,在维基百科文章部分阅读更多内容。
问题内容: 这似乎是一个非常基本的问题,但我找不到明确的确认。 假设我有一个本身已正确同步的类: 如果我需要 引用 在线程之间共享的该类的实例, 我仍然需要将该实例声明为volatile或final ,对吗?如: 或者,如果不能是最终的,则因为其实例化取决于其他一些事先未知的条件(与GUI的交互,来自套接字的信息等): final或volatile是强制性的 ,将访问权限同步到其自身成员的事实并不
问题内容: 我越来越。我提到了这个问题,它解决了我的问题。第一个答案是 我的问题是为什么我们需要在同一个对象广告上进行同步? 据我的理解,当我们说 我们锁定了对象someObject,然后对其调用了wait()。 现在,另一个线程如何才能锁定同一对象以在其上调用notify()? 我想念什么? 问题答案: 为什么也需要锁? 想象一下这种情况: 现在想象一下其他地方没有任何锁定: 乍一看,整个声音总
问题内容: 我有两个线程,我想确保我在LinkedBlockingQueue上正确进行了同步。这正确吗?还是不需要在(messageToCommsQueue)上进行显式同步? 宣言: 方法一: 方法二: 问题答案: 是的,没有必要。JavaDoc说: BlockingQueue实现是线程安全的。
我只在一个字符串对象上找到了同步的答案,而不是两个。 这不是一项真正的任务,而是一项任务。我有一个图书馆可以把钱从一个账户转到另一个账户。我无法访问帐户对象以锁定它。我只能用图书馆里的东西。传输(字符串从、字符串到),这不是线程安全的。我有一个帐户ID为字符串的方法。我需要在没有死锁的情况下锁定这两个字符串。 到目前为止,我所做的是: > 使用创建了新字符串。intern方法(字符串fr=from
问题内容: 我想知道如果在同一个对象上同步两次,在Java中是否会出现任何奇怪的行为? 场景如下 两种方法都使用该对象并对其进行同步。当第一个方法调用第二个方法时,它会被锁定而停止吗? 我不这么认为,因为它是同一个线程,但是我不确定是否可能会出现其他任何奇怪的结果。 问题答案: 同步块使用 可重入 锁,这意味着如果线程已经持有该锁,则它可以重新获取它而不会出现问题。因此,您的代码将按预期工作。 请
我对同步块有一些疑问。在提问之前,我想分享另一个相关帖子链接的答案,以回答相关问题。我引用彼得·劳里的同一个答案。 > <块引号> 同步确保您对数据有一致的视图。这意味着您将读取最新值,其他缓存将获得最新值。缓存足够智能,可以通过特殊总线相互通信(JLS不需要,但允许)该总线意味着它不必触摸主存储器即可获得一致的视图。 如果您只使用同步,则不需要Volatile。如果您有一个非常简单的操作,而同步