單例模式屬於對象創建型模式,其意圖是保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。對一些類來說,只有一個實例是很重要的,比如最近我的一個Android項目中用到一個數據庫管理類來封裝SQLite讀寫操作。我們知道,SQLite對多線程支持並不是很好,如果兩個線程同時操作數據庫,會報 "Database is locked" 的錯誤。我想到的解決辦法有兩個:一是運用同步機制,比如在一個線程類中對數據庫操作的部分加入 synchronized 關鍵字,這樣就可以確保該線程類的多個實例操作數據庫時不會發生沖突,但是如果兩個不同的線程類的實例在同一時刻操作數據庫時,用 synchronized 關鍵字就不處理不了了。發現 SQLiteDatabase 類中有一個 isDbLockedByOtherThreads() 方法,用來判斷一個數據庫對象是否被其他線程鎖定。由於我每次操作數據庫,都new一個SQLiteOpenHelper的實例,所以用 isDbLockedByOtherThreads() 方法的結果總是false。所以想到了第二種解決辦法,也就是在數據庫管理類中運用單例模式,這樣就保證了無論在哪個線程中獲取數據庫對象,都是同一個對象,那么就可在一個線程中用 isDbLockedByOtherThreads() 方法判斷數據庫是否被其他線程鎖定,如果是,則sleep等待,直至鎖被釋放。
以下Classroomdb 類正是運用了單例模式:
- public class Classroomdb extends SQLiteOpenHelper {
- private static final String DATABASE_NAME = "classroom.db";
- private static final int DATABASE_VERSION = 1;
- private static final String TABLE_NAME ="classroom_info";
- private static Classroomdb instance;
- public Classroomdb(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- }
- public static Classroomdb Instance(Context context) {
- if (instance == null) {
- instance = new Classroomdb(context);
- }
- return instance;
- }
- @Override//創建表
- public void onCreate(SQLiteDatabase db) {
- String sql = "CREATE TABLE " + TABLE_NAME
- + " (classroom_num, building, morning1, morning2, afternoon1, afternoon2, night1);";
- Log.i("createDB=", sql);
- db.execSQL(sql);
- // db.close();
- }
- @Override
- public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
- // TODO Auto-generated method stub
- }
- /*
- * 操作一
- */
- public void update(String[] classroom_num, String[] morning1, String[] morning2,
- String[] afternoon1, String[] afternoon2, String[] night1){
- // ......
- }
- /*
- * 操作二
- */
- public String[] readData(String time, String build) {
- // ......
- }
- /*
- * 操作三
- */
- public String[] getSingleClassroom(String roomNum) {
- // ......
- }
- }
在線程中就可如下來處理:
- Classroomdb db = Classroomdb.Instance(context);
- while (db.getWritableDatabase().isDbLockedByOtherThreads()) {
- Log.w("dblock", "db is locked by other threads!");
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }