2013-04-28 175 views
1

我知道互聯網上已經有很多類似的問題,但我的問題是關於我的代碼,而不是關於線程。我正在製作一個擁有玩家數據庫的小應用程序。數據存儲類的代碼如下。從java中的兩個線程同時訪問變量

public class DataManager 
{ 
static final int NO_OF_COLUMNS = 18; 
static QDatabase pdb; 

public DataManager() 
{ 
    pdb = new QDatabase(NO_OF_COLUMNS); 
} 

public void addPlayer(Object[] playerData) 
{ 
    pdb.add(playerData); 
} 

public void editPlayerInfo(int type, int playerRegNo, Object data) 
{ 
    pdb.set(type, playerRegNo, data); 
} 

public int getPlayerRegNo(String userID) 
{ 
    return (int) pdb.getData(USER_ID, userID, REG_NO); 
} 

public Boolean contains(int column, Object data) 
{ 
    return pdb.contains(column, data); 
} 
} 

我有不斷recieving來自多個客戶端的請求,並創造了他們每個人的一個新線程的服務器。他們都訪問這個基本上充當數據庫的DataManager類。在某種程度上,我是否有可能讓所有線程同時調用方法addPlayer()editPlayerInfo(),但由於同步問題而不能混淆整個事件?

我也知道我可以使用數據庫。但在這裏,我只是認爲這會更容易。假設將有大約200個線程同時運行。我解決這個問題的最好方法是什麼?

有沒有什麼辦法讓我所有的線程在同一時間訪問它,否則有200個線程相互等待可能會變得非常慢?

編輯1: 的QDatabase類如下:

public class QDatabase implements Serializable 
{ 
    private ArrayList<ArrayList<Object>> database; 
    public final int NOT_EXISTS = 0, REGULAR = 0, TRANSPOSE = 1; 
    private int lastid = -1; 

    //Initializer taking the number of columns as an argument 
    public QDatabase(int noofcolumns) 
    { 
     database = new ArrayList<ArrayList<Object>>(); 
     addColumns(noofcolumns); 
    } 

    //Method that adds an array of objects as a new row in the database. 
    public void add(Object[] object) 
    { 
     for(int index = 0; index < database.size(); index++) 
     { 
      if(object != null) 
      { 
       database.get(index).add(object[index]); 
       lastid = database.get(0).indexOf(object[0]); 
      } 
     } 
    } 

    //Method that finds the row in a column where an instance of a particular object is found and get the values at a 
    //cell with the same row and a given column. 
    public Object getData(int columntocheck, Object check, int columntoget) 
    { 
     Object ramobject = null; 

     int loc = database.get(columntocheck).indexOf(check); 
     ramobject = database.get(columntoget).get(loc); 

     return ramobject; 
    } 

    //Method to check if a column contains an instance of a given object. 
    public Boolean contains(int column, Object objecttocheck) 
    { 
     return database.get(column).contains(objecttocheck); 
    } 

    //Method to set a given cell to an object. 
    public void set(int column, int row, Object object) 
    { 
     database.get(column).set(row, object); 
    } 
} 

回答

1

QDatabase不是線程安全的。您需要同步所有方法或使用java.util.concurrent包中的ArrayList - CopyOnWriteArrayList的線程安全變體。但是要小心,只有當數據庫的讀取次數遠遠超過寫入次數時,使用CopyOnWriteArrayList纔有意義。請參閱API,它會爲所有可變操作創建一個新的無用數組副本。

UPDATE:

其實,在您的情況最有效的solutiion似乎是ReadWriteLock中。使用ReadLock進行所有讀取操作,使用WriteLock進行所有可變操作,像這樣

public class QDatabase implements Serializable { 
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); 
    private Lock readLock = readWriteLock.readLock(); 
    private Lock writeLock = readWriteLock.writeLock(); 
... 
    public void add(Object[] object) { 
     writeLock.lock(); 
     try { 
      ... 
     } 
     } finally { 
      writeLock.unlock(); 
     } 
    } 

    public Object getData(int columntocheck, Object check, int columntoget) { 
     readLock.lock(); 
     try { 
      ... 
     } finally { 
      readLock.unlock(); 
     } 
    } 
... 
+0

我需要多個線程來訪問相同的數據庫。它是一臺服務器。那麼,我需要做什麼? – Hele 2013-04-28 04:05:34

+0

保持原樣。這個類可以併發使用。 – 2013-04-28 04:08:50

+0

你能解釋一下這個類對於併發使用是否可行?如果兩個或多個線程同時調用editPlayerInfo會發生什麼情況? – Hele 2013-04-28 04:13:30

0

只需添加synchronized塊

public synchronized void addPlayer(Object[] playerData) 
{ 
    pdb.add(playerData); 
} 

public synchronized void editPlayerInfo(int type, int playerRegNo, Object data) 
{ 
    pdb.set(type, playerRegNo, data); 
} 

這將確保沒有兩個線程同時訪問這個方法。

+0

那很好,但有可能對我來說,讓這樣所有的線程可以在同一時間訪問數據庫? – Hele 2013-04-28 03:36:51

+0

@hele在這種情況下,請稍微改述一下您的要求。你想讓你的addPlayer和editPlayerInfo成爲線程安全,還是你希望它們同時訪問這些方法?所有線程將能夠同時訪問其他方法,而不是根據當前代碼來訪問這兩個方法。 – gurvinder372 2013-04-28 03:43:32

+0

我希望所有線程能夠同時訪問這些方法,並且不會因此造成任何問題。 – Hele 2013-04-28 03:45:37

0

多線程同時訪問但仍保持線程安全的方法之一是使用局部變量或使用ThreadLocal。 你的情況都不可行,所以你不能實現線程的同時訪問,它必須是順序的。

0

查看java.util.concurrency包。你可以使用那裏的類來更好地管理你的線程需求。

爲了使類/方法「線程安全」,必須這樣設計。現在,它並不清楚你的DATABASE對象在內部正在做什麼,但它看起來像來自方法名稱,多線程將成爲一個問題。

爲了增加線程數量,但不保持ENTIRE方法同步,查看添加/編輯方法實現的細節,是的,你必須限制線程訪問這些代碼行,這將導致的問題。

你可以使用像多讀原理,單寫鎖等

+0

關於多次讀取和單次寫入,只是寫入同步的方法和讀取方法不是,還是稍微複雜一點? – Hele 2013-04-28 04:07:22