Hele
Hele

Reputation: 1578

Accessing a variable concurrently from two threads in java

I am aware that there are already a lot of similar questions on the internet, but my question is about my code, NOT ABOUT THREADS. I am making a small app that has a database of players. The code of the data storing class is as follows.

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

I have a server which keeps on recieving requests from multiple clients and creating a new thread for each of them. They all access this DataManager class which essentially acts as a database. Will it be possible for me to, in some way, make it possible for all the threads to be able to call the addPlayer() and editPlayerInfo() methods at the same time and yet not mess the whole thing up due to synchronization problems?

I also know that I can use databases. But here, I just thought that this would be easier. Assume that there will be about 200 threads running simultaneously. What is the best way for me to solve this?

Is there any way for me to hve all the threads access it at the same time as otherwise having 200 threads to wait on each other might become very slow?

EDIT 1: The QDatabase class is as follows:

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

Upvotes: 2

Views: 2809

Answers (4)

Evgeniy Dorofeev
Evgeniy Dorofeev

Reputation: 136012

QDatabase is not thread-safe. You need either synchronize all its methods or use a thread-safe variant of ArrayList - CopyOnWriteArrayList from java.util.concurrent package. But be careful, using CopyOnWriteArrayList makes sense only if the number of reads from DB vastly outnumbers the number of writes. See API, it creates a fresh copy of unerlying array on all mutative operations.

UPDATE:

Actually, the most efficient solutiion in your situation seems to be ReadWriteLock. Use ReadLock for all reading operations and WriteLock for all mutative operations, like this

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

Upvotes: 1

nigel
nigel

Reputation: 33

Have a look at the java.util.concurrency package. You could use classes there to manage your threading needs better.

In order for a class/ method to be "thread safe" it has to be designed so. Now, its not clear what the DATABASE object you have is doing internally but it does look like from the method names , that multiple threads ARE going to be an issue.

In order to INCREASE the number of threads , yet not keeping the ENTIRE method synchronized, look into the details of the add/edit methods implementations and , yes you would have to limit thread access to those lines of code that would cause issues.

You could use principles like multiple READ ,single WRITE locks etc.

Upvotes: 0

Lokesh
Lokesh

Reputation: 7940

One of the ways to have simultaneous access by multiple threads but yet remain thread safe is to use local variables or use ThreadLocal. None of them is feasible in your case, so you can't achieve simultaneous access of thread, it has to be sequential.

Upvotes: 0

gurvinder372
gurvinder372

Reputation: 68393

just add synchronized block

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

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

It will make sure that no two threads will access this method at the same time.

Upvotes: 0

Related Questions