当前位置: 首页 > 面试题库 >

在不可变对象上同步(Java)

乐宜民
2023-03-14
问题内容

代码段-1

class RequestObject implements Runnable
{
    private static Integer nRequests = 0;

    @Override
    public void run()
    {       
        synchronized (nRequests)
        {
            nRequests++;
        }
    }
}

代码段-2

public class Racer implements Runnable
{
    public static Boolean won = false;

    @Override
    public void run()
    {
        synchronized (won)
        {
            if (!won)
            won = true;
        }
    }        
}

我在第一个代码段中遇到了竞争。我知道这是因为我正在获得对不可变对象(类型为Integer)的锁定。

我已经写了第二个代码片段,这再次使“布尔”不变。但这有效(输出运行中不显示竞争条件)。如果我正确理解了上一个问题的解决方案,则以下是出现问题的一种可能方法

  1. 线程1锁定由指向的对象(例如A) won
  2. 线程2现在试图获取由指向的对象的锁,won并进入A的等待队列。
  3. 线程1进入同步块,验证A是否为假,并通过说出won = true(A认为自己赢得了比赛)创建了一个新对象(例如B )。
  4. “ won”现在指向B。线程1释放了对象A的锁定(不再由指向won
  5. 现在,处于对象A等待队列中的线程2被唤醒,并获得了对对象A的锁定,而对象A仍然是false(不可变地)。现在进入同步块并假定它也赢了,这是不正确的。

为什么第二个代码片段一直都能正常工作?


问题答案:

synchronized (won)
{
if (!won)
won = true;
}


在这里,您有一个暂时的竞争条件,您不会注意到,因为它在第一次执行run方法后就消失了。在此之后,won变量不断指向的相同的实例Boolean表示true,其因此适当地用作互斥锁。

这并不是说您应该在实际项目中编写此类代码。应该将所有锁定对象分配给final变量,以确保它们永远不变。



 类似资料:
  • 问题内容: 代码段-1 代码段-2 尽管第二个代码段在不引起任何竞争条件的情况下运行良好,但第一个代码段未能成功同步同一类的不同实例(RequestObject)之间对静态数据成员的访问。有人可以对此进行更多说明。我想了解为什么第一种方法不起作用。 问题答案: 您将不断创建新的对象,然后对其进行同步,这至少使考虑它变得非常混乱。这样就可以得到以下情况: 线程A保持当前值(假设为0) 线程B排队等待

  • 问题内容: 我正在努力使可变对象与不可变对象有关。使用可变对象会带来很多负面影响(例如,从方法中返回字符串数组),但是我很难理解它的负面影响。使用可变对象的最佳实践是什么?您是否应尽可能避免使用它们? 问题答案: 好吧,这有几个方面。 没有参考身份的可变对象会在奇数时间导致错误。例如,考虑使用基于值的方法的 : 当实例用作键时,实例在映射中“丢失”,因为实例和相等性基于可变值。这些值在映射之外更改

  • 我试图理解java中同步块的概念。根据我读过的文档,我明白如果我们获取一个锁(使用实例变量的同步块),那么我们就不能在该类中的同一对象上获取同步锁。但是当我尝试实际使用以下片段时,我发现我的理解出了问题。 即我能够同时以两种不同的方法获取锁(同一实例变量上的同步块)。当线程启动时,它将转到run方法并无限期地等待,并且不会从同步块中出来。同时,如果我使用相同的线程调用stop方法,它会进入同步块并

  • 我只在一个字符串对象上找到了同步的答案,而不是两个。 这不是一项真正的任务,而是一项任务。我有一个图书馆可以把钱从一个账户转到另一个账户。我无法访问帐户对象以锁定它。我只能用图书馆里的东西。传输(字符串从、字符串到),这不是线程安全的。我有一个帐户ID为字符串的方法。我需要在没有死锁的情况下锁定这两个字符串。 到目前为止,我所做的是: > 使用创建了新字符串。intern方法(字符串fr=from

  • 问题内容: 我想知道如果在同一个对象上同步两次,在Java中是否会出现任何奇怪的行为? 场景如下 两种方法都使用该对象并对其进行同步。当第一个方法调用第二个方法时,它会被锁定而停止吗? 我不这么认为,因为它是同一个线程,但是我不确定是否可能会出现其他任何奇怪的结果。 问题答案: 同步块使用 可重入 锁,这意味着如果线程已经持有该锁,则它可以重新获取它而不会出现问题。因此,您的代码将按预期工作。 请

  • 我的目标是让Java对象不可变。我有一个班级< code >学生。为了实现不变性,我用以下方式对它进行了编码: 我的问题是,实现班级不变性的最佳方法是什么?