gpt4 book ai didi

java - 如何避免在非最终字段上同步?

转载 作者:行者123 更新时间:2023-11-30 10:56:56 25 4
gpt4 key购买 nike

如果我们有 2 个类在不同线程下对同一个对象进行操作,并且我们想避免竞争条件,我们将不得不使用具有相同监视器的同步块(synchronized block),如下例所示:

class A {
private DataObject mData; // will be used as monitor

// thread 3
public setObject(DataObject object) {
mData = object;
}

// thread 1
void operateOnData() {
synchronized(mData) {
mData.doSomething();
.....
mData.doSomethingElse();
}
}
}

class B {
private DataObject mData; // will be used as monitor

// thread 3
public setObject(DataObject object) {
mData = object;
}

// thread 2
void processData() {
synchronized(mData) {
mData.foo();
....
mData.bar();
}
}
}

我们将操作的对象将通过调用 setObject() 进行设置,之后它将不变。我们将使用该对象作为监视器。但是,intelliJ 会警告非最终字段上的同步。

在这种特殊情况下,非本地字段是否是可接受的解决方案?

上述做法的另一个问题是,不能保证监视器(mData)在被线程3设置后会被线程1或线程2观察到,因为“发生- before”关系在设置和读取显示器之间尚未建立。例如,它仍然可以被线程 1 观察为 null。我的猜测是否正确?

关于可能的解决方案,使 DataObject 线程安全不是一种选择。在类的构造函数中设置监视器并将其声明为 final 即可。

编辑 从语义上讲,所需的互斥与DataObject 相关。这就是我不想使用辅助显示器的原因。一种解决方案是在 DataObject 上添加 lock()unlock() 方法,这些方法需要在处理之前调用。在内部他们会使用一个 Lock 对象。因此,operateOnData() 方法变为:

 void operateOnData() {
mData.lock()
mData.doSomething();
.....
mData.doSomethingElse();
mData.unlock();
}

最佳答案

你可以创建一个包装器

class Wrapper
{
DataObject mData;

synchronized public setObject(DataObject mData)
{
if(this.mData!=null) throw ..."already set"
this.mData = mData;
}

synchronized public void doSomething()
{
if(mData==null) throw ..."not set"

mData.doSomething();
}

创建一个包装器对象并传递给 A 和 B

class A 
{
private Wrapper wrapper; // set by constructor

// thread 1
operateOnData()
{
wrapper.doSomething();
}

线程 3 也有对包装器的引用;它会在可用时调用 setObject()

关于java - 如何避免在非最终字段上同步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32852464/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com