昨天做了个HashMap缓存的测试,但这个测试代码应该还有点问题,我不知道应该怎么改,所以发上来给大家看看,希望有点帮助!
<code>
package task0919;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;/**
 * @author lzk
 * ConrurrentHashMap缓存测试程序
 *
 */
public class BufferHashMapTest {
private Statement stmt = null;
private Connection con = null;
private ResultSet rs = null;
private String drivce = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
private String URL = "jdbc:sqlserver://127.0.0.1:1433;DatabaseName = motortestv1";
public static ConcurrentHashMap updatehashmap = new ConcurrentHashMap();

public Connection getcon(){             //得到数据库连接
try{
Class.forName(drivce);
con = DriverManager.getConnection(URL,"sa","ba123");
}catch(Exception e){
System.out.println(e.getMessage());
}
return con;
}

public ConcurrentHashMap queryHashMap(String sql) throws Exception {      
ConcurrentHashMap conhashmap = new ConcurrentHashMap();
Connection con = new BufferHashMapTest().getcon();
stmt = con.createStatement();
rs = stmt.executeQuery(sql);
    
    while (rs.next()) {
     Integer array[] = new Integer[2];
     array[0] = rs.getInt(1);
     array[1] = rs.getInt(2);
     conhashmap.put(new Integer(array[0]), array[1]);
    }
    rs.close();
    return conhashmap;
}

public static void main(String []args){
String selectsql = "select id,status from users"; 
BufferHashMapTest bhmt = new BufferHashMapTest();

try{
ConcurrentHashMap conhashmap = bhmt.queryHashMap(selectsql);

new Login(conhashmap).start();    //启动登陆线程
new Logout(conhashmap).start();   //启动注销线程
new updateDB(bhmt).start();       //启动更新数据库线程
    }catch(Exception e){
     System.out.println("Error2 :"+e.getMessage());
    }
}
}class Login extends Thread{              //登陆线程
private ConcurrentHashMap conhashmap = null;

public Login(ConcurrentHashMap conhashmap){
this.conhashmap = conhashmap;
}

public void run(){
try{
while(true){
int id = (int)(Math.random()*1000+1);
int status = 1;             //status=1表示已经登陆
if(conhashmap.containsKey(id)){
int values = Integer.parseInt(conhashmap.get(id).toString());
if( values == status){
System.out.println("用户已经登陆!");
}else{
conhashmap.put(id, status);      //更新内存中conhashmap的当前信息
BufferHashMapTest.updatehashmap.put(id, status);  //临时保存更新信息
}
}else{
//System.out.println(id);
System.out.println("id不存在!");
}
Thread.sleep(3);
}
}catch(Exception e){
System.out.println("Error Login.run():"+e.getMessage());
}
}
}class Logout extends Thread{                 //注销线程
private ConcurrentHashMap conhashmap = null;

public Logout(ConcurrentHashMap conhashmap){
this.conhashmap = conhashmap;
}

public void run(){
try{
while(true){
int id = (int)(Math.random()*1000+1);
int status = 0; //status=0表示已经登出
if(conhashmap.containsKey(id)){
int values = Integer.parseInt(conhashmap.get(id).toString()); 
if(values == status){
System.out.println("用户已经注销!");
}else{
conhashmap.put(id, status);        //更新内存中conhashmap的当前信息
BufferHashMapTest.updatehashmap.put(id, status);  //临时保存更新信息
}
}else{
//System.out.println(id);
System.out.println("id不存在!");
}
Thread.sleep(5);
}
}catch(Exception e){
System.out.println("Error Logout.run()"+e.getMessage());
}
}
}class updateDB extends Thread{               //更新数据库线程 
private BufferHashMapTest bhmt = null;
private Connection conn= null;    
        private PreparedStatement pstmt = null;  
        private int length = 0; 

public updateDB(BufferHashMapTest bhmt){
this.bhmt = bhmt;
}

public void run(){
try{
while(true){
conn = bhmt.getcon();
length = bhmt.updatehashmap.size();
pstmt =conn.prepareStatement("UPDATE users SET status = ? WHERE id = ?");  
Set entryset = bhmt.updatehashmap.entrySet(); 
Iterator iter = entryset.iterator(); 

while(iter.hasNext()) { 
Map.Entry entry = (Map.Entry)iter.next(); 
int key = Integer.parseInt(entry.getKey().toString());
int value = Integer.parseInt(entry.getValue().toString());
System.out.print(key+" ");
System.out.println(value);
pstmt.setInt(1,value);
pstmt.setInt(2, key);
int tmp = pstmt.executeUpdate();
//System.out.println(tmp);
bhmt.updatehashmap.remove(key);         //更新数据库后移除临时hashmap中的元素
}
Thread.sleep(2000);
}
}catch(Exception e){
System.out.println("Error updateDB.run()"+e.getMessage());
}
}
}
</code>

解决方案 »

  1.   

    while(iter.hasNext()) { 
    Map.Entry entry = (Map.Entry)iter.next(); 
    int key = Integer.parseInt(entry.getKey().toString()); 
    int value = Integer.parseInt(entry.getValue().toString()); 
    System.out.print(key+" "); 
    System.out.println(value); 
    pstmt.setInt(1,value); 
    pstmt.setInt(2, key); 
    int tmp = pstmt.executeUpdate(); 
    //System.out.println(tmp); 
    bhmt.updatehashmap.remove(key);        //更新数据库后移除临时hashmap中的元素 
    } 这一行,楼主注意,迭代中删除会抛异常的ConcurrentModificationException
    bhmt.updatehashmap.remove(key);     
    Map是线性不安全的。
      

  2.   

    还有所有sql语句查询的地方,如果抛异常,数据库连接将无法关闭,导致连接泄漏多线程并发的情况没有考虑加锁,等等
      

  3.   

    支持楼上的意见,如果更新后需要删除临时记录,何不用个临时容器装起来,迭代结束后再进行删除操作,本来map就是非线性安全的
      

  4.   

    我那个hashmap是使用ConcurrentHashMap的,这个已是线程安全的吧?,
    我在网上找了很多ConcurrentHashMap的资料,说这个很好,呵呵!
      

  5.   


    参考jdk帮助文档,线性安全是不错,但是不加锁,你一边遍历一遍删除肯定是不可以的
    A hash table supporting full concurrency of retrievals and adjustable expected concurrency for updates. This class obeys the same functional specification as Hashtable, and includes versions of methods corresponding to each method of Hashtable. However, even though all operations are thread-safe, retrieval operations do not entail locking, and there is not any support for locking the entire table in a way that prevents all access. This class is fully interoperable with Hashtable in programs that rely on its thread safety but not on its synchronization details.