我知道互联网上已经有很多类似的问题,但我的问题是关于我的代码,而不是关于线程。我正在制作一个拥有玩家数据库的小应用程序。数据存储类的代码如下。
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);
}
}
答案 0 :(得分:1)
QDatabase不是线程安全的。您需要同步其所有方法或使用来自java.util.concurrent包的ArrayList - CopyOnWriteArrayList的线程安全变体。但是要小心,只有当来自DB的读取数量远远超过写入次数时,使用CopyOnWriteArrayList才有意义。请参阅API,它会在所有可变操作上创建一个新的无理数组副本。
<强>更新强>
实际上,您情况下最有效的解决方案似乎是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();
}
}
...
答案 1 :(得分: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);
}
它将确保没有两个线程同时访问此方法。
答案 2 :(得分:0)
多线程同时访问但保持线程安全的方法之一是使用局部变量或使用ThreadLocal。 在你的情况下,它们都不可行,因此你无法实现线程的同时访问,它必须是顺序的。
答案 3 :(得分:0)
查看java.util.concurrency包。您可以使用那里的类来更好地管理您的线程需求。
为了使类/方法成为“线程安全”,必须对其进行设计。现在,不清楚你的DATABASE对象在内部是做什么的,但它看起来与方法名称相似,多个线程将成为一个问题。
为了增加线程数,但不保持ENTIRE方法同步,请查看添加/编辑方法实现的详细信息,是的,您必须限制线程访问那些会导致问题的代码行。
您可以使用多个READ,单个WRITE锁等原则。