在java中从两个线程并发访问变量

在java中从两个线程并发访问变量,java,concurrency,synchronization,Java,Concurrency,Synchronization,我知道互联网上已经有很多类似的问题,但我的问题是关于我的代码,而不是关于线程。我正在制作一个有玩家数据库的小应用程序。数据存储类的代码如下所示 public class DataManager { static final int NO_OF_COLUMNS = 18; static QDatabase pdb; public DataManager() { pdb = new QDatabase(NO_OF_COLUMNS); } public void addPlayer(Ob

我知道互联网上已经有很多类似的问题,但我的问题是关于我的代码,而不是关于线程。我正在制作一个有玩家数据库的小应用程序。数据存储类的代码如下所示

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()
editplayernfo()
方法,而不会因为同步问题而把整个事情搞砸

我也知道我可以使用数据库。但在这里,我只是觉得这会更容易。假设大约有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);
    }
}
公共类QDatabase实现可序列化
{
私有ArrayList数据库;
公共final int NOT_EXISTS=0,REGULAR=0,TRANSPOSE=1;
private int lastid=-1;
//以列数为参数的初始值设定项
公共QDatabase(int noofcolumns)
{
数据库=新的ArrayList();
添加列(noofcolumns);
}
//方法,该方法将对象数组作为新行添加到数据库中。
公共无效添加(对象[]对象)
{
对于(int index=0;index
只需添加同步块

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

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

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

只需添加同步块即可

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

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

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

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

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

QDatabase不是线程安全的。您需要同步其所有方法,或者使用java.util.concurrent包中的ArrayList-CopyOnWriteArrayList的线程安全变体。但是要小心,只有当从DB读取的数量远远超过写入的数量时,使用CopyOnWriteArrayList才有意义。请参阅API,它会在所有变异操作上创建一个新的非递归数组副本

更新:

实际上,在您的情况下,最有效的解决方案似乎是读写锁定。对所有读取操作使用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();
        }
    }
...

QDatabase不是线程安全的。您需要同步其所有方法,或者使用java.util.concurrent包中的ArrayList-CopyOnWriteArrayList的线程安全变体。但是要小心,只有当从DB读取的数量远远超过写入的数量时,使用CopyOnWriteArrayList才有意义。请参阅API,它会在所有变异操作上创建一个新的非递归数组副本

更新:

实际上,在您的情况下,最有效的解决方案似乎是读写锁定。对所有读取操作使用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();
        }
    }
...

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

为了使类/方法是“线程安全的”,它必须这样设计。现在,还不清楚您的数据库对象在内部做什么,但从方法名称来看,多线程将是一个问题

为了增加线程的数量,但不保持整个方法的同步,请查看add/edit方法实现的详细信息,是的,您必须限制线程对可能导致问题的代码行的访问


您可以使用多读锁、单写锁等原则。

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

为了使类/方法是“线程安全的”,它必须这样设计。现在,还不清楚您的数据库对象在内部做什么,但从方法名称来看,多线程将是一个问题

为了增加线程数量,但不保持整个方法的同步,请查看add/edit方法实现的详细信息,是的,您必须将线程访问限制为