实现JDK没有提供的AtomicFloat

Java8内置了强大的多核支持,我们在处理数据的时候,如果不充分利用多核,都好不意思跟老板打招呼。

我们经常会使用AtomicInteger来做计数器,如下所示:

List<String> words = Files.readAllLines(Paths.get("src/main/resources/dic.txt"));
AtomicInteger i = new AtomicInteger();
words.parallelStream().forEach(word -> {
    //获取word的同义词、反义词以及相关词
    //......
    LOGGER.info("进度:" + total + "/" + i.incrementAndGet() + " 来自线程:" + Thread.currentThread());
});

在这段代码中,我们需要注意两点,一是parallelStream,二是变量i。

parallelStream的使用表示forEach中的代码段有可能会在不同线程中并发执行,因此变量i的incrementAndGet方法要保证是原子操作,否则计数器的数据就可能会出错。

没啥问题,一切都还很美好,so far so nice。

有一天,我们的需求复杂了,我们需要的计数器不仅仅只是+1,而是要支持小数,如2.5,3.1等等,这有什么大不了的,我们把AtomicInteger换成AtomicFloat不就支持小数了吗?

接着我们翻遍了JDK类库,都没有找到AtomicFloat,怎么回事呢?

最后终于在java.util.concurrent.atomic的package-summary.html页面的最后部分发现了秘密:

Additionally, classes are provided only for those types that are commonly useful in intended applications. For example, there is no atomic class for representing byte. In those infrequent cases where you would like to do so, you can use an AtomicInteger to hold byte values, and cast appropriately. You can also hold floats using Float.floatToRawIntBits(float) andFloat.intBitsToFloat(int) conversions, and doubles using Double.doubleToRawLongBits(double) andDouble.longBitsToDouble(long) conversions.

接下来我们就可以利用AtomicInteger作为基础来实现自己的AtomicFloat了,实现AtomicDouble和AtomicByte也是类似的做法,下面看看在word分词中实现的AtomicFloat

package org.apdplat.word.util;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 因为Java没有提供AtomicFloat
 * 所以自己实现一个
 * @author 杨尚川
 */
public class AtomicFloat extends Number {

    private AtomicInteger bits;

    public AtomicFloat() {
        this(0f);
    }

    public AtomicFloat(float initialValue) {
        bits = new AtomicInteger(Float.floatToIntBits(initialValue));
    }

    public final float addAndGet(float delta){
        float expect;
        float update;
        do {
            expect = get();
            update = expect + delta;
        } while(!this.compareAndSet(expect, update));

        return update;
    }

    public final float getAndAdd(float delta){
        float expect;
        float update;
        do {
            expect = get();
            update = expect + delta;
        } while(!this.compareAndSet(expect, update));

        return expect;
    }

    public final float getAndDecrement(){
        return getAndAdd(-1);
    }

    public final float decrementAndGet(){
        return addAndGet(-1);
    }

    public final float getAndIncrement(){
        return getAndAdd(1);
    }

    public final float incrementAndGet(){
        return addAndGet(1);
    }

    public final float getAndSet(float newValue) {
        float expect;
        do {
            expect = get();
        } while(!this.compareAndSet(expect, newValue));

        return expect;
    }

    public final boolean compareAndSet(float expect, float update) {
        return bits.compareAndSet(Float.floatToIntBits(expect), Float.floatToIntBits(update));
    }

    public final void set(float newValue) {
        bits.set(Float.floatToIntBits(newValue));
    }

    public final float get() {
        return Float.intBitsToFloat(bits.get());
    }

    public float floatValue() {
        return get();
    }

    public double doubleValue() {
        return (double) floatValue();
    }

    public int intValue() {
        return (int) get();
    }

    public long longValue() {
        return (long) get();
    }

    public String toString() {
        return Float.toString(get());
    }
}
时间: 2024-10-16 11:36:05

实现JDK没有提供的AtomicFloat的相关文章

使用jdk中提供的排序方式

package com.bjpowernode.t01; import java.util.Arrays; /** * 使用jdk中提供的排序方式 * */public class TestArray11 { public static void main(String[] args) { int[] a = {4,2,7,3,6}; //对数组进行排序 Arrays.sort(a); //升序输出// for(int i=0; i<a.length; i++) {// System.out.p

JDK 5 提供的注解

Retention注解 Retention(保留)注解说明,这种类型的注解会被保留到那个阶段. 有三个值: 1.RetentionPolicy.SOURCE -- 这种类型的Annotations只在源代码级别保留,编译时就会被忽略 2.RetentionPolicy.CLASS -- 这种类型的Annotations编译时被保留,在class文件中存在,但JVM将会忽略 3.RetentionPolicy.RUNTIME -- 这种类型的Annotations将被JVM保留,所以他们能在运行时

基于word分词提供的文本相似度算法来实现通用的网页相似度检测

实现代码:基于word分词提供的文本相似度算法来实现通用的网页相似度检测 运行结果: 检查的博文数:128 1.检查博文:192本软件著作用词分析(五)用词最复杂99级,相似度分值:Simple=0.968589 Cosine=0.955598 EditDistance=0.916884 EuclideanDistance=0.00825 ManhattanDistance=0.001209 Jaccard=0.859838 JaroDistance=0.824469 JaroWinklerDi

JDK自带方法实现RSA数字签名

JDK只支持MD2withRSA, MD5withRSA, SHA1withRSA 其他的如SHA512withRSA需要第三方包支持,如BC(bouncy castle) JDK的密钥长度默认仍是1024 1 package jdbc.pro.lin; 2 3 import java.security.InvalidKeyException; 4 import java.security.NoSuchAlgorithmException; 5 import java.security.Priv

JDK的并发容器

除了提供诸如同步控制,线程池等基本工具外,为了提高开发人员的效率,JDK已经为我们准备了一大批好用的并发容器,这些容器都是线程安全的,可以大大减少开发工作量.你可以在里面找到链表.HashMap.队列等.你可以在里面找到链表.HashMap.队列等. JDK提供的这些容器大部分在java.util.con-current包中. ?ConcurrentHashMap:这是一个高效的并发HashMap.你可以理解为一个线程安全的HashMap. ?CopyOnWriteArrayList:这是一个L

JDK动态代理和CGLIB动态代理

转载自http://www.itzhai.com/java-dong-tai-dai-li-zhi-jdk-dong-tai-dai-li-he-cglib-dong-tai-dai-li-mian-xiang-qie-mian-bian-cheng-aop-yuan-li.html 静态代理 静态代理相对来说比较简单,无非就是聚合+多态: 参考:设计模式笔记 – Proxy 代理模式 (Design Pattern) 动态代理 我们知道,通过使用代理,可以在被代理的类的方法的前后添加一些处理方

JAVA高并发程序设计学习-JDK并发包:同步控制一

JDK内部提供了大量的API和框架,这里主要介绍三部分 多线程同步控制方法 线程池,提高线程调度的性能 JDK的并发容器 重入锁:java.util.concurrent.locks.ReenterLock 在代码中,类ReenterLock实现了Runnable,其中有static的变量i,在run()方法中会对i进行自增操作. 自增操作的步骤为:get-set,先获取值再增加值. 如果在这里不进行控制的话,会导致get的值不是最新set的值. 因此,在自增的时候使用锁进行控制,保证get-s

JDK中的Timer和TimerTask详解

目录结构: Timer和TimerTask 一个Timer调度的例子 如何终止Timer线程 关于cancle方式终止线程 反复执行一个任务 schedule VS. scheduleAtFixedRate 一些注意点 1. Timer和TimerTask Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次. TimerTask是一个实现了Runnable接口的抽象类,代表一个可以被Timer执行的任务. 2.

eclipse启动时jdk环境变量的问题及解决办法

以前傻乎乎的,每次安装什么软件都是下载个windows安装文件,然后双击完exe文件就是一个劲儿的点下一步.知道完成,就心满意足的去使用了,后来发现机子卡了,垃圾多了,有些软件明明自己貌似没点安装竟然也有.当时觉得好神奇,现在才发现,那都是自己的问题.好了废话不多说了,接下来说下在本机没有安装JDK的情况下eclipse启动时报的错误及解决办法. eclipse(下载链接:[eclipse](http://pan.baidu.com/s/1mgu0COw)刚刚下载之后 如果没有安装JDK和配置环