您的位置:首页 > 数据库 > Redis

HashMap&&Redis Concurrent Problem

2015-07-20 16:16 585 查看
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);
}
}
}


这样的写法显然会造成高并发的线程的问题。

—-路漫漫其修远兮,吾将上下而求索!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: