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

4 回答 4

1

QDatabase 不是线程安全的。您需要同步其所有方法或使用 ArrayList 的线程安全变体 - java.util.concurrent 包中的 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();
        }
    }
...
于 2013-04-28T04:01:54.887 回答
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);
}

它将确保没有两个线程会同时访问此方法。

于 2013-04-28T03:29:35.120 回答
0

让多个线程同时访问但保持线程安全的方法之一是使用局部变量或使用 ThreadLocal。在您的情况下,它们都不可行,因此您无法实现线程的同时访问,它必须是顺序的。

于 2013-04-28T04:01:09.337 回答
0

看看 java.util.concurrency 包。您可以在那里使用类来更好地管理您的线程需求。

为了使一个类/方法是“线程安全的”,它必须这样设计。现在,尚不清楚您拥有的 DATABASE 对象在内部做什么,但从方法名称来看确实如此,多线程将成为一个问题。

为了增加线程数,但不保持整个方法同步,请查看添加/编辑方法实现的细节,是的,您必须限制线程访问那些会导致问题的代码行。

您可以使用多个 READ 、单个 WRITE 锁等原则。

于 2013-04-28T04:03:37.557 回答