HashMap&&Redis Concurrent Problem

来源:互联网 发布:精致的利己主义 知乎 编辑:程序博客网 时间:2024/06/15 18:54

1.前几天修改一个bug的时候发现一个Java数据结果并发的问题。大致过程如下:
其中Bean的数据结果如下,其中包含一个Map,主要是为了记录用户的使用次数。

public class Bean {    private Map<String,String> map = new HashMap<String,String>();    private String userId;    private int count = 0;    @Override    public int hashCode() {        final int prime = 31;        int result = 1;        result = prime * result + count;        result = prime * result + ((map == null) ? 0 : map.hashCode());        result = prime * result + ((userId == null) ? 0 : userId.hashCode());        return result;    }    @Override    public boolean equals(Object obj) {        if (this == obj)            return true;        if (obj == null)            return false;        if (getClass() != obj.getClass())            return false;        Bean other = (Bean) obj;        if (count != other.count)            return false;        if (map == null) {            if (other.map != null)                return false;        } else if (!map.equals(other.map))            return false;        if (userId == null) {            if (other.userId != null)                return false;        } else if (!userId.equals(other.userId))            return false;        return true;    }    @Override    public String toString() {        return "Bean [map=" + map + ", userId=" + userId + ", count=" + count + "]";    }    public Map<String, String> getMap() {        return map;    }    public void setMap(Map<String, String> map) {        this.map = map;    }    public String getUserId() {        return userId;    }    public void setUserId(String userId) {        this.userId = userId;    }    public int getCount() {        return count;    }    public void setCount(int count) {        this.count = count;    }    /**     * @param args     */    public static void main(String[] args) {        // TODO Auto-generated method stub    }}

Runnable:

public class TaskRunnable implements Runnable{    private int operationNumber;    public TaskRunnable(int a){        this.operationNumber = a;    }    @Override    public void run() {        Action action = new Action();        Bean bean = action.getAndUpdateBeanFromCache();        System.out.println("threadId is id = " + Thread.currentThread().getId());        if(bean==null){            bean = new Bean();            bean.setUserId("12344");            bean.setCount(11);        }        Map<String,String> map = bean.getMap();        map.put(operationNumber+"",operationNumber+"");        System.out.println("map key = " + operationNumber + " ," + " value = " + operationNumber);        RedisUtil.setCache(RedisConstant.testKey, new Gson().toJson(bean));    }}

Action:

public class Action {    public Bean getAndUpdateBeanFromCache(){        Bean bean = new Bean();        String key = RedisConstant.testKey;        String value = RedisUtil.getCache(key);        Type type = new TypeToken<Bean>(){}.getType();        bean = new Gson().fromJson(value,type);        return bean;    }}

MainClass:

public class MainClass {    public static void main(String[] args) throws InterruptedException {        for(int i = 0;i<100;i++){            Thread t = new Thread(new TaskRunnable(i)); //启动一百个线程测试            t.start();        }    }}

出现的问题,启动的一百个线程中并不是没有count都被记录下来,主要原因是因为HashMap这种数据结构在并发的时候存在一定的问题,但是如何解决这个问题,最后采用了Redis Hash Map的数据结构记录了用户的使用,经测试不会出现并发问题。主要原因是Redis是个单线程运行的程序,其中HashMap并不会出现这个并发的问题。

2.曾宪杰 大型网站系统与Java中间件实践
在这个本书中举出一个例子,跟这个很相似,如下:

public class TestClass {    private HashMap<String,Integer> map = new HashMap<String,Integer>();    public synchronized void add(String key){        Integer value = map.get(key);        if(value==null){            map.put(key, 1);        }else{            map.put(key, value+1);        }    }}

这个方法虽然能够正确的计数,但是在高并发的时候,却十分的影响性能,效率不高。将Map换成ConcurrentHashMap这个结构,代码如下:

public class TestClass {    private ConcurrentHashMap<String,Integer> map = new ConcurrentHashMap<String,Integer>();    public void add(String key){        Integer value = map.get(key);        if(value==null){            map.put(key, 1);        }else{            map.put(key, value+1);        }    }}

这样的写法显然会造成高并发的线程的问题。
—-路漫漫其修远兮,吾将上下而求索!

0 0
原创粉丝点击