1. 程式人生 > >一個JAVA單例模式的典型錯誤應用的分析和解決方法

一個JAVA單例模式的典型錯誤應用的分析和解決方法

               

問題來自論壇,

其程式碼如下:

[java] view plain copy print?
  1. import java.sql.Connection;  
  2. import java.sql.PreparedStatement;  
  3. import java.sql.ResultSet;  
  4. import java.sql.SQLException;  
  5. import com.cfd.drp.utils.Utils;  
  6. publicclass ClientManager {  
  7.   // 此處使用了例項級的屬性
  8.   StringBuffer sb = new StringBuffer();  
  9.   // 此處實現了單例模式
  10.   private
    static ClientManager manager = new ClientManager();  
  11.   private ClientManager() {  
  12.   }  
  13.   publicstatic ClientManager getInstance() {  
  14.     return manager;  
  15.   }  
  16.   // 這裡沒有同步,多個執行緒將同時呼叫這個方法
  17.   public String showTree() {  
  18.     Connection connection = null;  
  19.     sb.delete(0, sb.length());  
  20.     try {  
  21.       connection = Utils.getConnection();  
  22.       tree(connection, 01);  
  23.     } catch (Exception e) {  
  24.       e.printStackTrace();  
  25.     } finally {  
  26.       Utils.close(connection);  
  27.     }  
  28.     return sb.toString();  
  29.   }  
  30.   publicvoid tree(Connection connection, int id, int level) throws SQLException {  
  31.     String sql = "select * from t_client where pid = ?"
    ;  
  32.     int i = 0;  
  33.     PreparedStatement ps = null;  
  34.     ResultSet rs = null;  
  35.     try {  
  36.       ps = connection.prepareStatement(sql);  
  37.       ps.setInt(1, id);  
  38.       rs = ps.executeQuery();  
  39.       while (rs.next()) {  
  40.         sb.append(rs.getString("name") + "<br>" + "/n");  
  41.         if (rs.getString("is_leaf").equals("N")) {  
  42.           tree(connection, rs.getInt("id"), level);  
  43.         }  
  44.       }  
  45.     } finally {  
  46.       Utils.slose(rs);  
  47.       Utils.close(ps);  
  48.     }  
  49.   }  
  50. }  
import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import com.cfd.drp.utils.Utils;public class ClientManager {  // 此處使用了例項級的屬性  StringBuffer sb = new StringBuffer();  // 此處實現了單例模式  private static ClientManager manager = new ClientManager();  private ClientManager() {  }  public static ClientManager getInstance() {    return manager;  }  // 這裡沒有同步,多個執行緒將同時呼叫這個方法  public String showTree() {    Connection connection = null;    sb.delete(0, sb.length());    try {      connection = Utils.getConnection();      tree(connection, 0, 1);    } catch (Exception e) {      e.printStackTrace();    } finally {      Utils.close(connection);    }    return sb.toString();  }  public void tree(Connection connection, int id, int level) throws SQLException {    String sql = "select * from t_client where pid = ?";    int i = 0;    PreparedStatement ps = null;    ResultSet rs = null;    try {      ps = connection.prepareStatement(sql);      ps.setInt(1, id);      rs = ps.executeQuery();      while (rs.next()) {        sb.append(rs.getString("name") + "<br>" + "/n");        if (rs.getString("is_leaf").equals("N")) {          tree(connection, rs.getInt("id"), level);        }      }    } finally {      Utils.slose(rs);      Utils.close(ps);    }  }}

具體的錯誤我已經在程式碼裡標註出來了。

單例,就是系統只有一份例項,那麼多個執行緒使用這一個例項,當然也就同時使用這一個StringBuffer了。

大家一起胡亂的往裡面傾倒垃圾,怎麼可能不混亂呢!

解決方法就是將StringBuffer做成區域性變數

[java] view plain copy print?
  1. import java.sql.Connection;  
  2. import java.sql.PreparedStatement;  
  3. import java.sql.ResultSet;  
  4. import java.sql.SQLException;  
  5. import com.cfd.drp.utils.Utils;  
  6. publicclass ClientManager {  
  7.   // 此處實現了單例模式
  8.   privatestatic ClientManager manager = new ClientManager();  
  9.   private ClientManager() {  
  10.   }  
  11.   publicstatic ClientManager getInstance() {  
  12.     return manager;  
  13.   }  
  14.   // 這裡沒有同步,多個執行緒將同時呼叫這個方法
  15.   public String showTree() {  
  16.     // 此處使用區域性變數
  17.     StringBuffer sb = new StringBuffer();  
  18.     Connection connection = null;  
  19.     try {  
  20.       connection = Utils.getConnection();  
  21.       tree(connection, 01, sb); // 作為引數呼叫
  22.     } catch (Exception e) {  
  23.       e.printStackTrace();  
  24.     } finally {  
  25.       Utils.close(connection);  
  26.     }  
  27.     return sb.toString();  
  28.   }  
  29.   publicvoid tree(Connection connection, int id, int level, StringBuffer sb) throws SQLException {  
  30.     String sql = "select * from t_client where pid = ?";  
  31.     int i = 0;  
  32.     PreparedStatement ps = null;  
  33.     ResultSet rs = null;  
  34.     try {  
  35.       ps = connection.prepareStatement(sql);  
  36.       ps.setInt(1, id);  
  37.       rs = ps.executeQuery();  
  38.       while (rs.next()) {  
  39.         sb.append(rs.getString("name") + "<br>" + "/n");  
  40.         if (rs.getString("is_leaf").equals("N")) {  
  41.           tree(connection, rs.getInt("id"), level,sb);  
  42.         }  
  43.       }  
  44.     } finally {  
  45.       Utils.slose(rs);  
  46.       Utils.close(ps);  
  47.     }  
  48.   }  
  49. }  
import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import com.cfd.drp.utils.Utils;public class ClientManager {  // 此處實現了單例模式  private static ClientManager manager = new ClientManager();  private ClientManager() {  }  public static ClientManager getInstance() {    return manager;  }  // 這裡沒有同步,多個執行緒將同時呼叫這個方法  public String showTree() {    // 此處使用區域性變數    StringBuffer sb = new StringBuffer();    Connection connection = null;    try {      connection = Utils.getConnection();      tree(connection, 0, 1, sb); // 作為引數呼叫    } catch (Exception e) {      e.printStackTrace();    } finally {      Utils.close(connection);    }    return sb.toString();  }  public void tree(Connection connection, int id, int level, StringBuffer sb) throws SQLException {    String sql = "select * from t_client where pid = ?";    int i = 0;    PreparedStatement ps = null;    ResultSet rs = null;    try {      ps = connection.prepareStatement(sql);      ps.setInt(1, id);      rs = ps.executeQuery();      while (rs.next()) {        sb.append(rs.getString("name") + "<br>" + "/n");        if (rs.getString("is_leaf").equals("N")) {          tree(connection, rs.getInt("id"), level,sb);        }      }    } finally {      Utils.slose(rs);      Utils.close(ps);    }  }}