当前位置:   article > 正文

一次代码的优化经历_讲一下你在实际写代码过程中优化的经历

讲一下你在实际写代码过程中优化的经历

原始代码

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

/**
 * 实现方法 int count(String ip) 返回ip访问次数
 */
public class IpCount {
    static volatile ConcurrentHashMap<String, AtomicInteger> count = new ConcurrentHashMap<>();
    static final Object o = new Object();

    public static int count(String ip) {
        if (count.keySet().contains(ip)) {
            return count.get(ip).incrementAndGet();
        }
        synchronized (o) {
            if (count.keySet().contains(ip)) {
                return count.get(ip).incrementAndGet();
            } else {
                count.put(ip, new AtomicInteger(1));
                return 1;
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread[] threads = new Thread[10000];
        Random r = new Random();
        IpCount ipCount = new IpCount();
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                int ip = r.nextInt(5)+1;
                int a = ipCount.count(Integer.toString(ip));
            }, "t" + i);
        }
        for (Thread t : threads) {
            t.start();
        }
        Thread.sleep(5);
        System.out.println(ipCount.count);
        int sum  = 0;
        for (AtomicInteger value : ipCount.count.values()) {
            sum +=value.get();
        }
        System.out.println(sum);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

运行结果

在这里插入图片描述

  • 思路分析
  • 首先看到这些代码时,synchronized与Atomic同时使用
  • 也就是说,锁升级与CAS同时使用
  • Volatile的作用是 防止指令重排序和线程可见性
  • ConcurrentHashMap当调用时不存在出现半初始话状态
  • 这种极短的操作使用原子操作确实好很多,第一想法是synchronized去掉
  • 静态方法也没必要

去掉之后

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

/**
 * 实现方法 int count(String ip) 返回ip访问次数
 */
public class IpCount {
    ConcurrentHashMap<String, AtomicInteger> count = new ConcurrentHashMap<>();
    public int count(String ip) {
        if (count.keySet().contains(ip)) {
            return count.get(ip).incrementAndGet();
        } else {
            count.put(ip, new AtomicInteger(1));
            return 1;
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread[] threads = new Thread[10000];
        Random r = new Random();
        IpCount ipCount = new IpCount();
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                int ip = r.nextInt(5)+1;
                int a = ipCount.count(Integer.toString(ip));
            }, "t" + i);
        }
        for (Thread t : threads) {
            t.start();
        }
        Thread.sleep(5);
        System.out.println(ipCount.count);
        int sum  = 0;
        for (AtomicInteger value : ipCount.count.values()) {
            sum +=value.get();
        }
        System.out.println(sum);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

在这里插入图片描述
确实是出了一些问题,在意料之中

  • 到这里其实出现了沉思ConcurrentHashMap本身是线程安全的,为什么contains()会出现不安全了
  • 突然发现count.keySet().contains(ip)多出了一个keySet()
  • 尝试用count.containsKey(ip)替换count.keySet().contains(ip),也不正常
ConcurrentHashMap<String, AtomicInteger> count = new ConcurrentHashMap<>();
    public int count(String ip) {
        if (count.containsKey(ip)) {
            return count.get(ip).incrementAndGet();
        } else {
            count.put(ip, new AtomicInteger(1));
            return 1;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述

putIfAbsent()

但如果使用count.putIfAbsent()还会更优

  • 如何没有key对应的值,put
  • 如果已存在值依旧是原来的值,不做修改
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 实现方法 int count(String ip) 返回ip访问次数
 */
public class IpCount {
    ConcurrentHashMap<String, AtomicInteger> count = new ConcurrentHashMap<>();
    public int count(String ip) {
        count.putIfAbsent(ip, new AtomicInteger(0));
        return count.get(ip).incrementAndGet();
    }
    public static void main(String[] args) throws InterruptedException {
        Thread[] threads = new Thread[10000];
        Random r = new Random();
        IpCount ipCount = new IpCount();
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                int ip = r.nextInt(5)+1;
                int a = ipCount.count(Integer.toString(ip));
            }, "t" + i);
        }
        for (Thread t : threads) {
            t.start();
        }
        Thread.sleep(5);
        System.out.println(ipCount.count);
        int sum  = 0;
        for (AtomicInteger value : ipCount.count.values()) {
            sum +=value.get();
        }
        System.out.println(sum);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/148932
推荐阅读
相关标签
  

闽ICP备14008679号