2013-04-28 1 views
1

인터넷에 비슷한 질문이 많이 있다는 것을 알고 있지만 내 질문은 스레드에 관한 것이 아니라 내 코드에 관한 것입니다. 나는 선수 데이터베이스를 가지고있는 작은 앱을 만들고있다. 데이터 저장 클래스의 코드는 다음과 같습니다.자바의 두 스레드에서 동시에 변수에 액세스

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); 
} 
} 

나는 여러 클라이언트의 요청을 수신하고 각각에 대해 새 스레드를 만드는 서버가 있습니다. 그들은 모두 기본적으로 데이터베이스로 작동하는이 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를 사용하면 DB에서 읽는 횟수가 쓰기 횟수보다 훨씬 많을 때만 의미가 있습니다. API를 보면, 모든 돌연변이 연산에서 unerlying array의 새로운 사본을 생성합니다.

업데이트 :

사실, 현재 상황에서 가장 효율적인 solutiion가하는 ReadWriteLock 것 같다. 이

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

+0

그대로 두십시오. 이 클래스는 동시 사용에는 괜찮습니다. –

+0

동시 사용을 위해이 클래스의 사용법을 설명해 주시겠습니까? 2 개 이상의 스레드가 동시에 editPlayerInfo를 호출하면 어떻게됩니까? – Hele

0

그냥 그것은 두 개의 스레드가 동시에이 방법에 액세스하지 않을 것임을 확신합니다

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

그게 벌금 단일 WRITE 잠금을 사용할 수 있지만 그것은 나를 모든 스레드가 동시에 데이터베이스에 액세스 할 수는 있도록 할 수 있습니까? 이 경우 – Hele

+0

@hele을 사용하여 요구 사항을 약간 수정하십시오. addPlayer 및 editPlayerInfo가 threadSafe가되도록 하시겠습니까? 아니면이 메소드에 동시에 액세스하려고합니까? 모든 스레드는 동시에 다른 메소드에 액세스 할 수 있습니다. 현재 코드 당이 두 메소드는 없습니다. – gurvinder372

+0

나는 모든 스레드가 동시에 메서드에 액세스 할 수 있기를 원합니다.이 때문에 어떤 문제도 발생하지 않습니다. – Hele

0

여러 스레드에서 동시에 액세스 할 수 있지만 스레드 안전성을 유지하는 방법 중 하나는 로컬 변수를 사용하거나 ThreadLocal을 사용하는 것입니다. 이들 중 어느 것도 귀하의 경우에 실현 가능하지 않으므로 스레드의 동시 액세스를 얻을 수 없으므로 순차적이어야합니다.

0

처럼, 모든 변경 조작에 대한 모든 읽기 작업과 writeLock를위한 ReadLock 사용은 java.util.concurrency 패키지에서보세요. 거기에 클래스를 사용하여 스레딩 요구를보다 잘 관리 할 수 ​​있습니다.

클래스/메소드가 "스레드 안전성"을 가지려면 그렇게 설계되어야합니다. 이제, 당신이 가지고있는 DATABASE 객체가 내부적으로 무엇을하고 있는지 명확하지 않지만 메소드 이름처럼 보입니다. 다중 스레드가 문제가 될 것입니다.

스레드 수를 늘리려면 ENTIRE 메서드를 동기화하지 않은 상태에서 추가/편집 메서드 구현의 세부 사항을 살펴보고 스레드 액세스를 코드의 해당 줄로 제한해야합니다 문제.

여러 READ 같은 원칙 등

+0

다중 읽기 및 단일 쓰기에 관해서는 동기화하는 방법과 읽기 방법이 아닌 방법, 아니면 조금 더 복잡합니까? – Hele

관련 문제