关于线程和锁的问题

时间:2010-08-11 14:28:56

标签: java multithreading

现在我正在尝试更多地了解java线程,我有一个小问题,我找不到任何地方的直接答案。假设我有两个共享对象的线程:

public class FooA implements Runnable
{
    Object data;

    public FooA(final Object newData)
    {
        data = newData;
    }

    public void doSomething()
    {
        synchronized(data)
        {
            data = new Integer(1);
        }
    }

    public void run() {
        // Does stuff
    }
}

public class FooB implements Runnable
{
    Object data;

    public FooB(final Object newData)
    {
        data = newData;
    }

    public void doSomething()
    {
        synchronized(data)
        {
            System.out.println(data);
        }
    }
}

FooA会阻止FooB进入代码的doSomething部分吗?或相反亦然?我的直觉是肯定的,但根据我正在阅读的书,它说不。因此需要监控对象。我做了一个稍微复杂一点的版本,一切正常。

我环顾四周,但找不到具体的答案。

6 个答案:

答案 0 :(得分:3)

此示例存在一些问题。

首先,synchronized(data)表示它同时在data中的对象上进行同步。如果您使用相同的对象初始化了两个对象,则应该进行同步。

但是,由于您在代码中设置了data,因此在此之后实际上不会起作用(因为它不会是同一个对象)。

构造函数参数中的

final不是特别有用。作为场上的修饰语本身会更有用。它在这个特定的例子中不起作用,因为你正在修改这个值,但一般来说,当你知道要修复的值时,它是防止一些并发问题的好方法。

  

我做了一个稍微复杂的版本   这一切,一切正常。

通过反复试验来调试并发问题是非常困难的,或者几乎是不可能的。它没有失败的事实并不意味着它能够可靠地运作。

我建议您阅读本书:http://www.javaconcurrencyinpractice.com/

答案 1 :(得分:2)

问题是其中一个同步块会将新对象分配给data。如果该块首先启动,并且更改data,则后续运行将使用另一个对象来锁定。所以从那以后,两者都可以同时运行。

答案 2 :(得分:1)

在这种情况下答案是肯定的,但它很脆弱(即代码的下一次更改可能会破坏某些东西)。它为什么有效?

因为FooB从未注意到FooA更改了对象(每个线程都有自己的引用,所以FooBFooA为其引用分配新值时从不会注意到这一点。

对于这样的情况,我建议使用AtomicReference来确保两个线程可以访问同一个对象,任何人都可以随时更新该引用,其他线程只在更新后获取新值。 / p>

答案 3 :(得分:1)

任何Java对象都可用于同步。

如果FooA和FooB都是使用对同一对象的引用构造的,那么它们共享相同的“锁定”对象并将按预期阻塞。作为

  Object data;

decalrations不是最终的,无论是FooA还是FooB,或者两者都可以为数据分配不同的值,然后在不同的对象上进行同步 - 这可能是好的还是坏的,这取决于你想要做什么。

答案 4 :(得分:1)

在您的代码示例中,fooA.datafooB.data不是同一个对象,除非有人使用以下内容对其进行初始化:

Object o = new Object();
FooA fooA = new FooA(o);
FooB fooB = new FooB(o);

除非它们被初始化为同一个实例,否则它们不是同一个对象,只是相同的类型和名称。

FooAnew Integer(1)分配给data时,它们将不再是同一个对象,只是相同的类型和名称。因此,除非您致电:

,否则它们将不会同步
fooB.data = fooA.data;

这必须在同步块中发生以保证同步执行。

另外,关于线程的一些事情是,即使一切都工作一次,这并不意味着你的程序是正确的,或者每次都能正常工作。线程问题只发生在正确的时间恰好(或者只是错误的情况下)。

答案 5 :(得分:0)

只要您必须在同一个对象上进行同步,这是正确的,但由于一个线程修改了“data”引用的对象,因此您需要同步“this”。