lcx_1989210
2016-06-27 11:27
采纳率: 33.3%
浏览 1.7k
已采纳

关于AtomicInteger变量的一些疑问

本人最近写了一段代码,用到了AtomicInteger对这个变量,但是期待的结果与代码的实际运行
结果相差好大,现将代码奉上,求各位大牛给下解决方案。
class IDGeneration {
private final static ConcurrentHashMap idMap = new ConcurrentHashMap();

    private static final long baseTime = 1462377600000L;
    private Lock lock;

    IDGeneration() {
        lock = new ReentrantLock();
    }

    @SuppressWarnings("unused")
    public Long generateRelativeIncrementUniqueId(String flag) {
        String dateString = GengratedUnqueId.formatDate(new Date(),
                GengratedUnqueId.PATTERN);
        Long currentTime = (System.currentTimeMillis() - baseTime);
        AtomicInteger queueId = new AtomicInteger(0);
        int i = 0;
        Long tempValue = null;
        lock.lock();
        try {
            queueId = idMap.get(currentTime);
            if (queueId == null) {
                queueId = new AtomicInteger(0);
                idMap.clear();
                idMap.put(currentTime, queueId);
                tempValue = (currentTime << 5 | queueId.get());
            } else {
                queueId.getAndIncrement();
                idMap.put(currentTime, queueId);
                tempValue = (currentTime << 5 | queueId.get());
            }
        } finally {
            lock.unlock();
        }
        return tempValue;
        return null;
    }
}


这是测试代码:
public static void main(String[] args) throws Exception {
static ConcurrentHashMap<Long, String> map = new ConcurrentHashMap<Long, String>();

    final IDGeneration idGeneration = new IDGeneration();
    for (int i = 0; i < 100; i++) {

        Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {

                long value = idGeneration
                        .generateRelativeIncrementUniqueId();
                map.put(value, "");
            }
        });
        thread.start();

    }
    TimeUnit.SECONDS.sleep(5);
    System.out.println("map.size===" + map.size());
    }
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

5条回答 默认 最新

  • _1_1_7_ 2016-06-29 01:18
    已采纳

    先说最早的版本:
    // idMap.clear();
    这行代码注释掉就可以了,少的部分其实是被你自己清除了,同步上是够了;

    后面你改的,缺少同步,多线程不安全,改如下:

     public Long generateRelativeIncrementUniqueId() {
            long tempValue = (System.currentTimeMillis() - baseTime);
            long value = 0;
            AtomicInteger queueId = map.get(tempValue);
            if (queueId == null) {
                // 这里需要同步,因为map中还没有queueId
                synchronized (this) {
                    // 需要再检验一遍
                    queueId = map.get(tempValue);
                    if (queueId == null) {
                        queueId = new AtomicInteger(0);
                        map.put(tempValue, queueId);
                    }
                }
                value = (tempValue << 8 | queueId.getAndIncrement());
            } else {
                // queueId.getAndIncrement();
                // map.put(tempValue, queueId);//没必要
                value = (tempValue << 8 | queueId.getAndIncrement());
            }
            System.out.println(tempValue + "," + queueId.get());
            return value;
        }
    
    点赞 打赏 评论
  • _1_1_7_ 2016-06-28 01:59

    逻辑就很大问题,全局变量和局部变量也没划分清楚,
    特别: Long currentTime = (System.currentTimeMillis() - baseTime);
    这个时间基本每次都不一样了,还需要缓存在idMap吗?

    点赞 打赏 评论
  • _1_1_7_ 2016-06-28 02:50

    我简化了代码:

    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicInteger;

    public class SimpleID {

    private static final long baseTime = 1462377600000L;
    
    public static void main(String[] args) throws Exception {
        final ConcurrentHashMap<Long, String> map = new ConcurrentHashMap<Long, String>();
    
        final SimpleID idGeneration = new SimpleID();
        for (int i = 0; i < 100; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    long value = idGeneration.generateRelativeIncrementUniqueId();
                    map.put(value, "");
                }
            });
            thread.start();
    
        }
        TimeUnit.SECONDS.sleep(5);
        System.out.println("map.size===" + map.size());
    }
    
    private AtomicInteger queueId = new AtomicInteger(0);
    
    public Long generateRelativeIncrementUniqueId() {
        Long tempValue = baseTime + queueId.getAndIncrement();
        return tempValue;
    }
    

    }

    
    

    AtomicInteger足够了,它本身是没问题的,这样你就可以好好理解AtomicInteger了

    点赞 打赏 评论
  • lcx_1989210 2016-06-28 03:42

    public Long generateRelativeIncrementUniqueId() {
    long tempValue = (System.currentTimeMillis() - baseTime);
    long value = 0;
    queueId = map.get(tempValue);
    if (queueId == null) {
    queueId = new AtomicInteger(0);
    map.put(tempValue, queueId);
    value = (tempValue << 8 | queueId.get());
    } else {
    queueId.getAndIncrement();
    map.put(tempValue, queueId);
    value = (tempValue << 8 | queueId.get());
    }
    System.out.println(tempValue + "," + queueId.get());
    return value;
    }

    这是处理方法的逻辑,main方法保持不变。运行结果后:map.size===95
    下边的图片是几个重复的queueId的值。
    
    ![图片说明](https://img-ask.csdn.net/upload/201606/28/1467085304_869998.png)
    
    点赞 打赏 评论
  • lcx_1989210 2016-06-28 03:44

    这是图片的部分重复数据的内容:
    4707077338,0
    4707077338,0
    4707077338,2
    4707077338,1
    4707077339,0
    4707077339,2
    4707077339,2

    点赞 打赏 评论

相关推荐 更多相似问题