Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java线程安全:当必须调用实例变量上的方法时,如何处理实例变量_Java_Multithreading - Fatal编程技术网

Java线程安全:当必须调用实例变量上的方法时,如何处理实例变量

Java线程安全:当必须调用实例变量上的方法时,如何处理实例变量,java,multithreading,Java,Multithreading,因此,当涉及到代码的线程安全性时,我总体上是相当不错的,但我目前遇到的情况是,我不清楚如何最好地处理它 我有一个实例变量,非final,因为封闭类可以更改其值。这个变量是一个对象,它有几个方法在应用程序中被调用。这里有一个简单的例子来说明我的意思 private class Foo{ private FooFoo fooFoo; public synchronized void setFooFoo(FooFoo fooFoo){ thi

因此,当涉及到代码的线程安全性时,我总体上是相当不错的,但我目前遇到的情况是,我不清楚如何最好地处理它

我有一个实例变量,非final,因为封闭类可以更改其值。这个变量是一个对象,它有几个方法在应用程序中被调用。这里有一个简单的例子来说明我的意思

private class Foo{

        private FooFoo fooFoo;

        public synchronized void setFooFoo(FooFoo fooFoo){
            this.fooFoo = fooFoo;
        }

        public void doSomething(){
            fooFoo.doSomething(); //How do I make this line thread-safe?
        }

    }
更改foooo字段的引用很容易,只是简单的同步。但是,当对fooo调用doSomething()方法时会发生什么呢?由于存在死锁风险,我总是犹豫是否在异类方法上进行同步

在实际案例中,这是基于,有许多不同的变化。我公司的应用程序是一个庞大的代码库,经常像一碗意大利面条,所以当涉及到编写任何类型的同步代码时,我都会特别偏执,因为紧密耦合,而且事实上不仅仅在美国有开发人员,但在东欧的一家从事it的离岸公司,我不相信他们所有人都能做出好的编码决策


所以我只是在寻找在多线程环境中处理这种情况的最佳实践。谢谢。

在您的情况下,您还必须使
doSomething()
同步化,因为每次发生对类的可变部分的并发访问时,您都需要锁定。当您仅在
doSomething
中读取
foooo
时,您可以同时在
setfoooo()
中写入
foooo
,从而创建数据竞争
synchronized
基本上会导致函数调用在进入时获取与Java对象相关联的锁,并在离开函数后释放它

或者,您可以在
Foo
中使用
Lock
成员,您可以在执行任何操作时使用该成员。这适用于以下情况:您可能有多个独立的成员,在另一个成员被更改时可以安全地访问这些成员。在这种情况下,使用两个不同的锁可能会使代码大大加快

为了完整起见,应该提到的是,在一些较旧的Java版本中(我相信只有Java 5),通过
synchronized
方法获取对象的内部锁要比使用锁对象慢得多


<死锁问题>:你担心这是正确的,但是在你首先让你的对象线程安全之后,把它当作一个单独的问题来考虑。问题是还有什么其他锁被采取,这是不可能的回答这仅仅是你张贴。对于您的对象,同步对象上的读/写操作本身不会死锁,因为此时只能有一个操作处于活动状态,并且它们不会从您在代码中显示的内容中获取任何其他锁。

这取决于您对线程安全的关注程度

如果foo只是委托给你,你可以简单地让它变得不稳定。这将防止线程在更新引用时兑现对旧值的引用。FooFoo可以处理自己的线程安全问题

private class Foo{

    private volatile FooFoo fooFoo;

    public void setFooFoo(FooFoo fooFoo){
        this.fooFoo = fooFoo;
    }

    public void doSomething(){
        fooFoo.doSomething();
    }

}
如果您关心的是Foo本身的线程安全,而它所做的不仅仅是委派调用,那么您应该同步相关的方法

private class Foo{

    private FooFoo fooFoo;

    public synchronized void setFooFoo(FooFoo fooFoo){
        this.fooFoo = fooFoo;
    }

    public synchronized void doSomething(){
        fooFoo.doSomething();
    }

    public synchronized void doSomethingElse() {
        int values = fooFoo.getValue();
        // do some things
        fooFoo.setValue(values + somethingElse);
    }
}
foooo.doSomething()//如何使这条线线程安全

提示:除非这是整个程序中访问对象的唯一一行,否则不能使这一行线程安全

线程安全不是使特定的代码行或特定的方法线程安全:而是使数据线程安全

fooFoo是指可变对象吗?如果不是,那么该行已经是线程安全的。但是如果对象是可变的,那么线程安全至少意味着确保两个或多个线程之间的非预期交互不会使该对象进入无效状态;在最坏的情况下,它意味着确保
foooo
对象与程序中其他对象之间关系的一致性


当线程之间共享的两个或多个数据段之间存在重要关系时,您可能需要在可能临时违反该关系的任何代码位周围抛出一个
synchronized
块,您需要在依赖于该关系的任何代码位周围抛出一个
synchronized
块,即使代码只查看数据。

为什么您认为这是
死锁风险
?为什么您认为方法doSomething()的简单同步无法工作,而对setFooo()来说已经足够了?如果将synchronized关键字放在两个方法上,则锁将位于同一个对象上,因此不会出现死锁,如果线程
A
和线程
B
都同时调用
setfooo
,您希望发生什么?如果线程
C
当时调用
foooo.doSomething()
,您希望发生什么。即使没有同步化,此场景也不会导致崩溃。您在第二个示例中忘记同步其他方法。目前,后者甚至不能为您提供必要的可见性保证。