`

类中字段赋值给局部变量后再使用意义何在

    博客分类:
  • jdk
 
阅读更多
Concurrency-interest邮件列表中有人问了这么一个问题:ArrayBlockingQueue中有个对象字段lock,在ArrayBlockingQueue的很多方法中,使用这个lock时都将其先赋值给一个局部变量,然后再通过局部变量调用lock上的方法,而没有直接使用lock字段,如remainingCapacity方法中先将this.lock赋值给一个局部变量lock,然后再使用这个局部变量:
public class ArrayBlockingQueue {
	private final ReentrantLock lock;
	
	//...other fields and methods
	
	public int remainingCapacity() {
		final ReentrantLock lock = this.lock;
		lock.lock();
		try {
			return items.length - count;
		} finally {
			lock.unlock();
		}
	}
}

而不是像这样直接使用类中的字段:
public class ArrayBlockingQueue {
	private final ReentrantLock lock;
	
	//...other fields and methods
	
	public int remainingCapacity() {
		this.lock.lock();
		try {
			return items.length - count;
		} finally {
			this.lock.unlock();
		}
	}
}

那么为什么要这么做,有什么理由或说法?


Doug Lea给出了回复,大意如下:
引用

归根究底是由于内存模型与OOP之间的原则不一致。

几乎j.u.c包中的每个方法都采用了这样一种策略:当一个值会被多次使用时,就将这个字段读出来赋值给局部变量。虽然这种做法不雅观,但检查起来会更直观。

final字段也会做这样处理,可能有些令人不解。这是因为JVM并不足够智能,不能充分利用JMM已经提供了安全保证的可优化点,比如可以不用重新加载final值到缓存。相比过去,JVM在这方面有很大进步,但仍不够智能。


原文如下:

引用
It’s ultimately due to the fundamental mismatch between memory models
and OOP :-)

Just about every method in all of j.u.c adopts the policy of reading fields as locals whenever a value is used more than once.This way you are sure which value applies when.This is not often pretty, but is easier to visually verify.

The surprising case is doing this even for “final” fields.This is because JVMs are not always smart enough to exploit the fine points of the JMM and not reload read final values, as they would otherwise need to do across the volatile accesses entailed in locking. Some JVMs are smarter than they used to be about this, but still not always smart enough.


source: http://ifeve.com/fields-and-local/
分享到:
评论

相关推荐

    优质资源汇总【更新ing...】

    方法的返回值是方法执行后的结果,返回值在类的方法里可以被用于其他方法或变量赋值。 2. 为什么 Java 中只有值传递? Java 中只有值传递,因为 Java 中的参数传递是值传递的。 3. 重载和重写的区别: 重载是...

    Java面试题以及答案

    - **this()**:在同一个类的构造方法中使用,用于调用该类的另一个构造方法。同样地,它也必须是构造方法中的第一条语句。 #### 2. 作用域public, protected, private,以及不写时的区别? - **public**:公共访问...

    2021-2022计算机二级等级考试试题及答案No.12658.docx

    形参变量是属于被调方法的局部变量,而实参变量一般是属于主调方法的局部变量。”是**正确**的。 ### 22. 面向对象的概念 **知识点描述:** 面向对象编程的基本概念及其要素。 **详细解释:** - 面向对象编程 (OOP...

    java面试宝典

    唯一的限制是,内部类不能直接访问外部类实例的局部变量。 **28. AnonymousInnerClass(匿名内部类) 是否可以extends(继承) 其它类,是否可以implements(实现) interface(接口)?** 匿名内部类可以实现接口或继承...

    PowerBuilder9.0教程_pb9_PB9.0_

    - **局部变量与全局变量**:理解局部变量仅在当前作用域内有效,而全局变量在整个应用程序中都可访问。 - **数组变量**:如何声明和使用数组变量,以及数组元素的访问方式。 - **变量的作用域和生命周期**:掌握变量...

    CSharp Language Specification

    允许在字符串或字符中使用 Unicode 转义序列。 **2.4.2 标识符** 标识符用于命名类型、变量、方法等。 **2.4.3 关键字** 关键字具有特殊的含义,在程序中有固定的用途。 **2.4.4 字面量** 字面量是指直接在源代码...

    C#语言规范1.2版

    - **方法体和局部变量**:方法的主体以及在方法中声明的变量。 - **静态和实例方法**:静态方法不依赖于任何对象,实例方法则依赖于对象。 - **虚方法、重写方法和抽象方法**:虚方法可以在派生类中重写,抽象方法...

    2021-2022计算机二级等级考试试题及答案No.16177.docx

    19. 局部内部类:局部内部类可以访问其所在方法或块的局部变量,但必须在该变量是final的情况下。 20. URL含义:URL(Uniform Resource Locator)是统一资源定位符,用于标识互联网上的资源。 21. 标签控件字体...

    java面试题大集合

    - `final`修饰的变量一旦赋值后就不能改变。 #### 十一、继承时候类的执行顺序问题 在Java中,类的继承顺序遵循以下规则: 1. 首先执行父类的构造器。 2. 然后执行子类自己的构造器。 3. 如果子类构造器中显式调用...

    三种修饰符有何目标?

    它可以应用于属性、局部变量、方法和类。常量一旦被赋值,就不能再改变。对于属性,如果定义为 `final` 并且没有初始化,那么必须在声明时或静态初始化块中赋值。`final` 方法不能被子类重写,确保了方法的行为不会...

    《你必须知道的495个C语言问题》.pdf

    **3.12 我需要根据条件把一个复杂的表达式赋值给两个变量中的一个。可以用下边这样的代码吗?** - 不推荐使用复杂的条件赋值表达式,因为难以阅读和维护。 - 最好将条件和赋值分开,提高代码的清晰度。

    进入IT企业必读的200个+.NET面试题.pdf )

    - GC通过根对象(如静态字段、局部变量等)追踪可达的对象。未被任何根对象直接或间接引用的对象被视为不再使用。 - **3.2.7 .NET的托管堆中是否可能出现内存泄漏现象?** - 虽然GC管理内存,但在某些情况下仍...

    Microsoft.Net常见问题集锦

    栈用于存放局部变量和方法调用的信息,分配和释放速度快,但容量有限。 21. **成员变量和成员函数前加 static 的作用?** - 加上 `static` 关键字表示该成员属于类而不是实例。静态成员只有一份拷贝供所有对象共享...

    JAVA程序员面试高频题

    - **栈内存**:方法执行时的局部变量。 - **方法区**:存放类信息,如常量池。 - **JVM调优**:理解GC算法,设置JVM参数优化程序性能。 9. **设计模式** - **单例模式**:确保一个类只有一个实例。 - **工厂...

    Review of Java and object-oriented programming.ppt

    Java 和面向对象编程是计算机科学中的核心概念,尤其在软件开发领域中占据着重要的地位。以下是对这些概念的详细说明: ### Java 语言基础 **Java 的数据类型** Java 包括两种主要的数据类型:基本类型(Primitive...

    34个java问题.pdf

    - **局部变量**:方法内的变量,作用范围仅限于该方法。 #### 19. 创建一个对象用什么运算符?对象实体与对象引用有何不同? - **运算符**:使用`new`关键字创建对象。 - **对象实体与引用**:对象实体是在堆内存...

    java面试题(尚学堂内部培训资源,绝对值得一看)

    - **stack**:栈内存,用于存放局部变量和方法调用的临时数据。 #### 63. Static Nested Class和Inner Class的不同? - **Static Nested Class**:静态嵌套类,无需依赖外部类实例,可通过类名直接访问。 - **...

Global site tag (gtag.js) - Google Analytics