我们是否同步最终的实例变量?如果是的话有什么用?

发布于 2024-08-19 19:00:25 字数 53 浏览 3 评论 0原文

我想知道我们是否同步最终的实例变量。由于变量是最终变量,因此值不能更改。 有人能解释一下吗?

I like to know do we synchronize the instance variable which are final. As variables are final there can not be change in the value.
Can anybody explain this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

三五鸿雁 2024-08-26 19:00:25

我们是否同步最终的实例变量?

是的。你还是要同步可变对象

final != immutable

 public class Something {
     private final List list = new ArrayList();

     public void add( String value ) {
         this.list.add( value );
     }
     public int count() {
          return this.list.size();
     }
 }

稍后

 Something s = new Something();

 Thread a = new Thread() {
    public void run(){
       s.add( "s" );
       s.add( "s" );
       s.add( "s" );
     }
 };
 Thread b = new Thread(){
     public void run() {
         s.count();
         s.count();
     }
 };

 a.start();
 b.start();

如果是的话有什么用?

您声明,给定的属性在对象生命周期内不能更改。

这提高了安全性(您的对象属性不能被恶意子类替换)
允许编译器优化(因为它知道只会使用引用)
防止子类更改它等等。

既是最终属性又是不可变属性(如字符串、整数等)不需要同步。

class X {
    private final String name = "Oscar";

    public int nameCount(){
        return this.name.length(); //<-- Will return 5 ALWAYS ( actually the compiler might inline it 
    }
 }

Do we synchronize instance variables which are final?

Yes. You still have to synchronize mutable objects

final != immutable

 public class Something {
     private final List list = new ArrayList();

     public void add( String value ) {
         this.list.add( value );
     }
     public int count() {
          return this.list.size();
     }
 }

Later

 Something s = new Something();

 Thread a = new Thread() {
    public void run(){
       s.add( "s" );
       s.add( "s" );
       s.add( "s" );
     }
 };
 Thread b = new Thread(){
     public void run() {
         s.count();
         s.count();
     }
 };

 a.start();
 b.start();

If yes then whats the use?

You're declaring, that a given attribute can't be changed during the object life time.

This increases the security ( your object attribute can't be replaced by a malicious subclass )
Allows compiler optimizations ( because it knows that only a reference will be used ever )
Prevents subclasses from changing it and so on.

An attribute that is both, final and immutable ( like String, Integer and others ) doesn't need synchronization.

class X {
    private final String name = "Oscar";

    public int nameCount(){
        return this.name.length(); //<-- Will return 5 ALWAYS ( actually the compiler might inline it 
    }
 }
末蓝 2024-08-26 19:00:25

一个重要的例外:final 字段在对象构造后无法修改,但一旦对象构造完毕,就可以通过非同步方法安全地读取

取自 同步方法

An important exception: final fields, which cannot be modified after the object is constructed, can be safely read through non-synchronized methods, once the object is constructed

Taken from Synchronized Methods

年少掌心 2024-08-26 19:00:25

如果访问器方法返回最终变量的值,您通常不会将其标记为“同步”;例如,

private final String message = "Hello, World";

// No need to mark as synchronized as message can never change.
public String getMessage() {
  return message;
}

但是,您可能希望同步最终变量,例如,如果您将其用作锁;例如

private final Object lock;

...

synchronized(lock) {
  // Do something in critical section.
}

You typically would not mark accessor methods as synchronized if the method was returning the value of a final variable; e.g.

private final String message = "Hello, World";

// No need to mark as synchronized as message can never change.
public String getMessage() {
  return message;
}

However, you may wish to synchronize on the final variable, for example if you were using it as a lock; e.g.

private final Object lock;

...

synchronized(lock) {
  // Do something in critical section.
}
|煩躁 2024-08-26 19:00:25

如果实例变量不是不可变的,那么即使该变量是最终变量,其状态仍然可以更改。举个例子:

private final List<Foo> foos = new ArrayList<Foo>();


public void addFoo(Foo newFoo){
      foos.add(newFoo);
}

public Foo popFoo(){
     return foos.remove(0);
}

在这种情况下,即使 foos 是最终的,当线程 A 尝试删除元素时,线程 B 也可以添加 Foo,这可能会导致一致状态。

其他示例中提到的同步方法教程是正确的,因为读取最终变量不需要同步。但是,如果变量是可变的(如 List 那样),则必须同步对该变量的写入,以保证“发生之前”关系。但是,如果变量是不可变的,那么当然不允许对该变量进行写入,因此不需要同步。

If the instance variable isn't immutable, then the state of that variable can still be changed even if it is final. Take, for example:

private final List<Foo> foos = new ArrayList<Foo>();


public void addFoo(Foo newFoo){
      foos.add(newFoo);
}

public Foo popFoo(){
     return foos.remove(0);
}

In this situation, even though foos is final, a Foo can be added by Thread B while Thread A is attempting to remove an element, leading to potentially iconsistent state.

The Sychronized Methods tutorial mentioned in other examples is correct in that reading a final variable does not need to be sychronized. However, if the variable is mutable(as List<T> is), then writing to that variable must be synchronized to guarantee a "happens-before" relationship. If, however, the variable is immutable, then of course writes are not allowed to that variable anyway, so there is no need to synchronize.

路弥 2024-08-26 19:00:25

嗯,是的。当您使用引用类型声明最终实例变量时,该引用是不可变的,但它引用的对象通常是可变的。如果可能有多个线程访问和更新可变对象的状态,则需要同步对最终实例的操作。

例如:

public class Thing {
   private final List l1 = 
   private final List l2 = 
   private final List l3 = 

   ...

   public void l1ToL2() {
       l2.add(l1.removeFirst());
   }

   public void l2ToL3() {
       l3.add(l2.removeFirst());
   }
}

如果我们不采取措施来同步这些方法对 l1l2l3 的使用,那么它们就不是线程安全的,并且来自不同线程的并发操作可能会损坏列表。

另一方面,由于 @Anthony Forloney 的回答中所述的原因,这是线程安全的。

public class Thing {
   private final int i = ... ;

   public int getI() {
       return i;
   }
}

Well yes. When you declare a final instance variable with a reference type, the reference is immutable but the object it refers to typically is mutable. If there may be multiple threads accessing and updating the state of mutable object, the operations on the final instance need to be synchronized.

For example:

public class Thing {
   private final List l1 = 
   private final List l2 = 
   private final List l3 = 

   ...

   public void l1ToL2() {
       l2.add(l1.removeFirst());
   }

   public void l2ToL3() {
       l3.add(l2.removeFirst());
   }
}

If we don't do something to synchronize those methods' use of l1, l2 and l3, they are not thread-safe, and concurrent operations from different threads could corrupt the lists.

On the other hand, this is thread-safe, for the reasons stated in @Anthony Forloney's answer.

public class Thing {
   private final int i = ... ;

   public int getI() {
       return i;
   }
}
Oo萌小芽oO 2024-08-26 19:00:25

无需同步对最终实例变量的访问。

请参阅 http://java.sun.com/docs/books /tutorial/essential/concurrency/syncmeth.html

同步方法启用了一种防止线程干扰和内存一致性错误的简单策略:如果一个对象对多个线程可见,则对该对象变量的所有读取或写入都会完成通过同步方法。 (一个重要的例外:final 字段在对象构造后无法修改,一旦构造了对象,就可以通过非同步方法安全地读取)这种策略是有效的,但可能会带来活性问题,因为我们将请参阅本课稍后内容。

There is no need to synchronize access to final instance variables.

see http://java.sun.com/docs/books/tutorial/essential/concurrency/syncmeth.html

Synchronized methods enable a simple strategy for preventing thread interference and memory consistency errors: if an object is visible to more than one thread, all reads or writes to that object's variables are done through synchronized methods. (An important exception: final fields, which cannot be modified after the object is constructed, can be safely read through non-synchronized methods, once the object is constructed) This strategy is effective, but can present problems with liveness, as we'll see later in this lesson.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文