并发包compareAndSet的疑惑?为什么没有对应的compare,If Not Equals,Then Set的方法呢?...

本文探讨了并发包中compareAndSet方法的工作原理及其应用场景,并解释了为何没有提供compare,IfNotEquals,ThenSet方法的原因,即这种操作未被CPU直接支持。
public final boolean compareAndSet(boolean expect,boolean update)
如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。

  并发包的这个方法,看起来意思是compare,If Equals,Then Set

我有个疑惑,为什么没有对应的compare,If Not Equals,Then Set的方法呢 ?

比如,以下场景,就无法使用compareAndSet:

if(a != b){
  a = b;
}

if(a != c){
  a = b;
}

 

因为我觉得,compare,If Equals,Then Set 和 compare,If Not Equals,Then Set 是不能互相实现对方的,所以应该要有另外的方法才完整。

 

 

查到了:原来是因为compareAndSet是cpu支持的,没有 compare,If Not Equals,Then Set是因为cpu不支持。

http://tomyz0223.iteye.com/blog/770677

<think>我们有两个问题需要回答: 1. Java中Double.compare方法的作用 2. 为什么使用包装类Double而不是基本类型double 参考引用: 引用[1]:Double类是原始类型double的包装类,它包含若干有效处理double值的方法,如将其转换为字符串表示形式,反之亦然。Double类的对象可以包含一个double值。主要有两个构造函数来初始化Double对象 -[^1]。 引用[2]:以下是Java中的包装类及其对应的基本数据类型: Byte:byteShort:shortInteger:intLong:longFloat:floatDouble:doubleCharacter:charBoolean:boolean [^2]。 引用[3]:Float是float的包装类,需要注意的是Float虽然提供了compareequals方法,但是需要注意要比较的数是否在精度范围内,否则会发生数值不相等compare却为0或equals为true的情况。另外,应该静止使用浮点数来作为循环变量。[^3] 首先,回答第一个问题:Double.compare方法的作用。 Double.compare是Double类的一个静态方法,用于比较两个double值。它的方法签名如下: public static int compare(double d1, double d2) 作用:比较两个double数值,返回一个整数值来表示大小关系: - 如果d1在数值上等于d2,则返回0。 - 如果d1小于d2,则返回负整数(通常是-1)。 - 如果d1大于d2,则返回正整数(通常是1)。 为什么要使用Double.compare而不是直接使用关系运算符(如<, >, ==)? 因为double是浮点数,存在一些特殊值(如NaN)和精度问题。直接使用关系运算符比较两个double值可能会出现问题,例如: - NaN(非数字)与任何值(包括它自己)比较,使用关系运算符都会返回false,而使用Double.compare则规定:NaN等于NaN(但实际上,根据IEEE 754标准,NaN与任何值比较都不相等,包括自身。但Java的Double.compare方法将NaN视为相等?实际上不是,我们来看一下官方文档)。 实际上,根据Java文档,Double.compare方法对NaN的处理如下: - 如果d1和d2都是NaN,则返回0(即相等)。 - 如果d1是NaN而d2不是,则返回1(即d1大于d2?这里注意,实际上NaN在比较中应该被认为大于任何非NaN的数值?但根据文档:Double.NaN被认为等于自身,并且大于所有其他double值(包括Double.POSITIVE_INFINITY))。 - 如果d2是NaN而d1不是,则返回-1(即d1小于d2)。 另外,正零和负零在比较时被认为是相等的(即0.0 == -0.0为true,但Double.compare(0.0, -0.0)返回0?实际上,根据IEEE标准,正零和负零在数值上是相等的,所以返回0。但是注意,在某些情况下,比如使用equals方法,Double对象会认为0.0和-0.0是不同的,但Double.compare方法认为相等。 所以,使用Double.compare可以正确处理所有情况,包括NaN和正负零。 第二个问题:为什么使用包装类Double而不是基本类型double? 包装类的主要用途包括: 1. 在需要对象而非基本类型的场合使用。例如,在集合类(如ArrayList)中,只能存储对象,不能存储基本类型。因此,如果我们想将double值放入一个List中,就必须使用Double包装类。 2. 提供了一些有用的方法。例如,Double类提供了将字符串解析为double的方法(Double.parseDouble),以及将double转换为字符串的方法(Double.toString)。此外,还有比较方法(如compare)、常量(如MAX_VALUE、MIN_VALUE、NaN)等。 3. 允许null值。基本类型double不能为null,而Double对象可以为null。这在某些场景下是有用的,比如表示缺失值(但要注意空指针异常)。 4. 在泛型中必须使用包装类,因为Java泛型不支持基本类型。 但是,使用包装类也有一些缺点: - 包装类对象比基本类型占用更多的内存(因为对象有对象头等开销)。 - 自动装箱和拆箱可能会带来性能开销(尽管在大多数情况下可以忽略)。 所以,在需要对象特性或使用泛型时,我们使用包装类;而在需要高性能和节省内存时,我们使用基本类型。 结合引用[3]中提到的浮点数比较问题:由于浮点数的精度问题,直接使用==比较两个double值可能会出现问题(尤其是经过计算后)。因此,比较两个double值通常使用一个误差范围(epsilon)。但是,Double.compare方法内部也是使用关系运算符,并且对特殊值(如NaN)进行了处理,但它并不解决精度问题。对于需要精度控制的比较,我们通常使用如下方式: Math.abs(a - b) < epsilon 但是,Double.compare方法并不考虑精度,它严格按照数值大小比较(包括处理特殊值)。所以,如果两个double值非常接近但在二进制表示上不同,Double.compare会认为它们不相等。 总结: - Double.compare方法用于比较两个double值,并正确处理NaN和正负零。 - 包装类Double在需要对象、泛型、null值或使用Double类的方法时使用。 下面给出一个代码示例: ```java public class DoubleComparisonExample { public static void main(String[] args) { double d1 = Double.NaN; double d2 = Double.NaN; double d3 = 0.0; double d4 = -0.0; // 使用关系运算符 System.out.println(d1 == d2); // false,因为NaN不等于任何值,包括自身 System.out.println(d3 == d4); // true,正零和负零在数值上相等 // 使用Double.compare System.out.println(Double.compare(d1, d2)); // 0,表示相等 System.out.println(Double.compare(d3, d4)); // 0,表示相等 // 比较一个NaN和一个非NaN System.out.println(Double.compare(d1, d3)); // 1,因为NaN被认为大于任何非NaN值 System.out.println(Double.compare(d3, d1)); // -1 } } ``` 输出: false true 0 0 1 -1 注意:在引用[3]中提到,浮点数比较要注意精度问题,所以如果两个double值是通过计算得到的,并且我们允许一定的误差,那么就不应该使用Double.compare,而应该使用误差范围比较。但是,Double.compare在需要严格按数值比较(如排序)时非常有用。 最后,生成相关问题: 1. 在Java中,如何正确比较两个浮点数(float或double)? 2. Java自动装箱和拆箱机制是什么?它如何影响性能? 3. 为什么在集合类中不能使用基本数据类型? 4. Double类中还有哪些常用的静态方法?</think>### Java中`Double.compare()`方法的作用及包装类的必要性 #### 1. `Double.compare()`方法详解 `Double.compare(double d1, double d2)`是Java中用于安全比较两个double值的静态方法,其核心作用包括: ```java // 方法签名 public static int compare(double d1, double d2) ``` **返回值含义**: - 返回负数:当 $d1 < d2$ - 返回0:当 $d1 = d2$ - 返回正数:当 $d1 > d2$ **特殊值处理机制**: | 场景 | 返回值 | 说明 | |--------------------------|--------|----------------------------------------------------------------------| | 两个NaN比较 | 0 | 认为NaN相等(不同于 `==` 运算符)[^3] | | NaN与任何非NaN值比较 | 1 | NaN被视为大于所有数值(包括无穷大) | | 正零(0.0)和负零(-0.0)比较| 0 | 认为数值相等(符合IEEE 754标准) | | 常规数值比较 | 按实际值 | 如 `compare(3.14, 2.71)` 返回正数 | **与运算符比较的区别**: ```java double nan = Double.NaN; double inf = Double.POSITIVE_INFINITY; // 错误方式(结果违反直觉) System.out.println(nan == nan); // false ❌ System.out.println(nan > inf); // false ❌ // 正确方式 System.out.println(Double.compare(nan, nan) == 0); // true ✅ System.out.println(Double.compare(nan, inf) > 0); // true ✅ ``` #### 2. 为何使用包装类Double 基本类型`double`与包装类`Double`的核心区别: | 特性 | `double`基本类型 | `Double`包装类 | |------------------|------------------|-------------------------| | 存储方式 | 栈内存 | 堆内存(对象) | | 默认值 | 0.0 | `null` | | 集合支持 | 不支持 | 支持(如List<Double>) | | 特殊值处理 | 有限 | 完整API支持(如NaN) | | 附加功能 | 无 | 比较/转换/常量等方法 | **必须使用包装类的场景**: 1. **泛型集合操作** ```java List<Double> prices = new ArrayList<>(); // 必须用包装类 prices.add(19.99); ``` 2. **特殊值处理** 需要表示缺失值时: ```java Double temperature = null; // 有效表示"未测量" // double temp = null; // 编译错误 ``` 3. **对象方法调用** 需要调用比较方法时: ```java Double.compare(d1, d2); // ✅ 正确 // d1.compareTo(d2); // ❌ 基本类型无此方法 ``` 4. **API兼容性** 反射等API要求对象类型: ```java Method method = Double.class.getMethod("isNaN"); method.invoke(Double.valueOf(0.0/0.0)); // 返回true ``` #### 3. 浮点数比较的精度问题 虽然`Double.compare()`能正确处理特殊值,但**不解决精度问题**: ```java double a = 0.1 + 0.2; // ≈0.30000000000000004 double b = 0.3; // 0.3 // 精度问题导致错误结果 System.out.println(a == b); // false ❌ System.out.println(Double.compare(a, b)); // 1 (认为a>b) ❌ // 正确做法:使用误差范围 boolean isEqual = Math.abs(a - b) < 1e-10; // true ✅ ``` #### 4. 完整使用示例 ```java import java.util.*; public class DoubleComparisonDemo { public static void main(String[] args) { // 创建含特殊值的Double列表 List<Double> values = Arrays.asList( 3.14, Double.NaN, 0.0, -0.0, Double.POSITIVE_INFINITY, 1.0/0.0 ); // 使用Double.compare排序 Collections.sort(values, Double::compare); // 输出排序结果 [-0.0, 0.0, 3.14, ∞, ∞, NaN] System.out.println(values); } } ``` #### 5. 关键结论 1. `Double.compare()`: - 正确处理NaN、无穷大等特殊值 - 符合IEEE 754浮点数标准 - 适用于排序等需要确定顺序的场景[^1] 2. 包装类必要性: - 实现对象化操作(如集合存储) - 支持null值表示数据缺失 - 提供完整API(比较/转换/校验等)[^2] - 满足泛型要求(如`List<Double>`)[^2] 3. 精度警示: - 浮点数计算存在固有精度问题 - 比较相等时需使用误差范围 $|a-b| < \epsilon$ - 避免用浮点数作为循环计数器[^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值