How to design a 2D array in java in such a way that it allows multiple threads to modify or insert value at a particular position without using synchronization
Well you cannot do it without synchronization. Only thing you can do is reduce the scope of he lock used. If you don't know yet, read about lock coarsening. ConcurrentHashMap uses it. Idea is that instead of locking the whole array to modifications you just lock a segment of array (e.g: start, middle or end) where the modification would happen. This keeps the array DS open for reads and writes by other threads and no blocking happens unless 2 threads try to mutate the same segment simultaneously.
There are several ways to do it.
Firstly, if you want maximum concurrency as a common library regardless of how many threads are accessing the matrix, and your int[][] is reasonably small, you can do like this.
Set up a matrix of AtomicBoolean equals to the dimension of the int[][].
While you are trying to update the int matrix, lock that AtomicBoolean first, the use Unsafe.putIntVolatile() to update the value in volatile way, then unluck the AtomicBoolean.
Secondly, if you know the number of threads in advance.
Keep a marker object/value as per thread like int; then create an additional int[][] as the marker matrix. Initialize the marker matrix to some dummy value which doesn't equal to any of your thread marker value, e.g. -1.
While you are trying to update the int matrix, lock the cell in thr marker matrix by using Unsafe.compareAndSet() first; then update it by Unsafe.putIntVolatile(); and finally unmark the marker matrix by reset the value to -1.
Lastly, if you can tolerate the int[][] isn't really an int matrix in the actual code, what you can do is to use a long[][] matrix, where the first 32 bit is the current number of updates to the value and the last 32 bit is the current value. Then you can easily use Unsafe.compareAndSet() to set this long value as a whole. Note you can circular the upper 32 bit value so you don't have to have a update upper limit == Integer.MAX_VALUE.
Does this question make sense? If we assume an int[][] all operations on it will be atomic so there should be no need for synchronization! But what confuses me on the question: you cannot insert values in means of changing the array bounds after you have declared it.
If you can guarantee that each element of the array(s) is only ever accessed by a single thread (until you completed the computation that can change the array(s) contents), then you can safely use many threads. (because they will be effectively independent) Otherwise, it's probably a bad idea…
Create a static variable that can be accessed by all your Threads like:
public class MainClass {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
public void run() {
Constants.intValue[0][0] = new Integer(10);
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
Constants.intValue[0][1] = new Integer(20);
}
});
Thread t3 = new Thread(new Runnable() {
public void run() {
for (Integer[] valueArr : Constants.intValue) {
for (Integer intValue : valueArr) {
System.err.println(intValue);
}
}
}
});
t1.start();
t2.start();
t3.start();
}
}
interface Constants {
Integer[][] intValue = new Integer[2][2];
}
The only case will be next thread will override previous set value if it is using the same array position.
Related
This question already has answers here:
Java MultiThreading skips loop and gives wrong result [duplicate]
(3 answers)
Closed 1 year ago.
I'm java beginner and it's first time to use thread.
class Counter2 {
private int value = 0;
public void increment() {
value++;
printCounter();
}
public void decrement() {
value--;
printCounter();
}
public void printCounter() {
System.out.println(value);
}
}
class MyThread3 extends Thread {
Counter2 sharedCounter;
public MyThread3(Counter2 c) {
this.sharedCounter = c;
}
public void run() {
int i = 0;
while (i <= 100) {
sharedCounter.increment();
sharedCounter.decrement();
try {
sleep((int) (Math.random() * 2));
} catch (InterruptedException e) {
}
// System.out.println(i);
i++;
}
}
}
public class MyTest {
public static void main(String[] args) {
Thread t1, t2;
Counter2 c = new Counter2();
t1 = new MyThread3(c);
t1.start();
t2 = new MyThread3(c);
t2.start();
}
}
This code has 2 threads and 1 Counter, which is shared between the threads. The threads just repeat plus 1, minus 1 to the counter value. So, if I guess, the result should be 0. Because initial value was 0 and the number of incremented and decremented are the same. But some times the last printing number is not the 0, but -1 or -2 etc. please explain why this is this.
The Answer by Ranwala is correct.
AtomicInteger
An alternative solution I prefer is the use of the Atomic… classes. Specifically here, AtomicInteger. This class is a thread-safe wrapper around an integer.
Change your member field from Counter2 sharedCounter; to AtomicInteger sharedCounter;. Then use the various methods on that class to increment, to decrement, and to interrogate for current value.
You can then discard your Counter2 class entirely.
Executors
Also, you should know that in modern Java, we rarely need to address the Thread class directly. Instead we use the executors framework added to Java 5.
Define your tasks as either a Runnable or Callable. No need to extend from Thread.
See tutorial by Oracle, and search existing posts here on Stack Overflow.
There are two issues here. They are atomicity and visibility aspects of concurrency. Both increment and decrement are compound actions and need to be atomically performed in a multi-threaded environment. Apart from that you should not read a stale value whenever you read the counter. None of these are guaranteed by your current implementation.
Coming back to the solution, one naive way of achieving this is by using synchronized methods which uses a lock on the current instance to achieve the thread-safety. But that comes at a fairly high cost and incurs more lock overhead.
A much better approach would be to use CAS based non-blocking synchronization to achieve the task at hand. Here's how it looks in practice.
class Counter2 {
private LongAdder value = new LongAdder();
public void increment() {
value.increment();;
printCounter();
}
public void decrement() {
value.decrement();;
printCounter();
}
public void printCounter() {
System.out.println(value.intValue());
}
}
Since you are a beginner, I would recommend you to read the great book Java Concurrency in Practice 1st Edition which explains all these basics in a very nice, graspable manner by some of the great authors in our era ! If you have any questions about the contents of the book, you are welcome to post the questions here too. Read it from cover to cover at least twice !
Update
CAS is so called ComparaAndSwap is a lock free synchronization scheme achieved by using low level CPU instructions. Here it reads the value of the counter before the increment/decrement and then at the time it is updated, it checks whether the initial value is still there. If so, it updates the value successfully. Otherwise, chances are that another thread concurrently updating the value of the counter, hence the increment/decrement operation fails and it retries it again.
class ThreadUnsafe {
static final int THREAD_NUMBER = 2;
static final int LOOP_NUMBER = 200;
public static void main(String[] args) {
ThreadUnsafe test = new ThreadUnsafe();
for (int i = 0; i < THREAD_NUMBER; i++) {
new Thread(() -> {
test.method1(LOOP_NUMBER);
}, "Thread" + i).start();
}
}
ArrayList<String> list = new ArrayList<>();
public void method1(int loopNumber) {
for (int i = 0; i < loopNumber; i++) {
method2();
method3();
}
}
private void method2() {
list.add("1");
}
private void method3() {
list.remove(0);
}
}
The code above throws
java.lang.IndexOutOfBoundsException: Index: 0, Size: 1
I know ArrayList is not thread-safe, but in the example, I think every remove() call is guaranteed to be preceded by at least one add() call, so the code should be OK even the order is messed up like the following:
thread0: method2()
thread1: method2()
thread1: method3()
thread0: method3()
Some explanations needed here, please.
If always one add() or remove() call is completely finished before another one is started, your reasoning is correct. But ArrayList doesn't guarantee that as its methods aren't synchronized. So, it can happen that two threads are in the middle of some modifying calls at the same time.
Let's look at the internals of e.g. the add() method to understand one possible failure mode.
When adding an element, ArrayList increases the size using size++. And this is not atomic.
Now imagine the list being empty, and two threads A and B adding an element at exactly the same moment, doing the size++ in parallel (maybe in different CPU cores). Let's imagine things happen in the following order:
A reads size as 0.
B reads size as 0.
A adds one to its value, giving 1.
B adds one to its value, giving 1.
A writes its new value back into the size field, resulting in size=1.
B writes its new value back into the size field, resulting in size=1.
Although we had 2 add() calls, the size is only 1. If now you try to remove 2 elements (and this time it happens sequentially), the second remove() will fail.
To achieve thread safety, no other thread should be able to mess around with the internals like size (or the elements array) while one access is currently in progress.
Multi-threading is inherently complex in that the calls from multiple threads can not only happen in any (expected or unexpected) order, but that they can also overlap, unless protected by some mechanism like synchronized. On the other hand, excessive use of the synchronization can easily lead to poor multi-thread performance, and also to dead-locks.
As a supplement to #RalfKleberhoff's answer,
I think every remove() call is guaranteed to be preceded by at least one add() call,
Yes.
so the code should be OK even the order is messed up
No, that is not a valid inference with respect to a multithreaded program.
Your program contains data races as a result of two threads both accessing the same shared, non-atomic object, with some of those accesses being writes, without appropriate synchronization. The whole behavior of a program that contains data races is undefined, so in fact you cannot draw any conclusions at all about its behavior.
Do not try to cheat or scrimp on synchronization. Do minimize the amount of it that you need by limiting your use of shared objects, but where you need it, you need it, and the rules for determining when and where you need it are not that hard to learn.
ArrayList in java docs says,
Note that this implementation is not synchronized. If multiple threads
access an ArrayList instance concurrently, and at least one of the
threads modifies the list structurally, it must be synchronized
externally.
Why this code is not thread safe ?
Multiple thread running on Machine runs independent of each other.
public void method1(int loopNumber) {
for (int i = 0; i < loopNumber; i++) {
method2();
method3();
}
}
Here method2() and method3() are being process sequential within
the thread but not across the thread. ArrayList list is common between both thread. which will be in inconstant state between both thread on multi core system.
Interesting test would be add empty check in method3() and set LOOP_NUMBER = 10000;
private void method3()
{
if (!list.isEmpty())
list.remove(0);
}
In result you should get same Runtime Exception some thing like java.lang.IndexOutOfBoundsException: Index: 0, Size: 1 or java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 because of same reason inconstant state of variable in list i.e. size.
To fix this issue you could have added synchronized like below or use Syncronized list
public void method1(int loopNumber)
{
for (int i = 0; i < loopNumber; i++)
{
synchronized (list)
{
method2();
method3();
}
}
}
im trying to write a program in which two threads are created and the output should be like 1st thread prints 1 and the next thread prints 2 ,1st thread again prints 3 and so on. im a beginner so pls help me clearly. i thought thread share the same memory so they will share the i variable and print accordingly. but in output i get like thread1: 1, thread2 : 1, thread1: 2, thread2 : 2 nd so on. pls help. here is my code
class me extends Thread
{
public int name,i;
public void run()
{
for(i=1;i<=50;i++)
{
System.out.println("Thread" + name + " : " + i);
try
{
sleep(1000);
}
catch(Exception e)
{
System.out.println("some problem");
}
}
}
}
public class he
{
public static void main(String[] args)
{
me a=new me();
me b=new me();
a.name=1;
b.name=2;
a.start();
b.start();
}
}
First off you should read this http://www.oracle.com/technetwork/java/codeconventions-135099.html.
Secondly the class member variables are not shared memory. You need to explicitly pass an object (such as the counter) to both objects, such that it becomes shared. However, this will still not be enough. The shared memory can be cached by the threads so you will have race-conditions. To solve this you will need to use a Lock or use an AtomicInteger
It seems what you want to do is:
Write all numbers from 1 to 50 to System.out
without any number being printed multiple times
with the numbers being printed in order
Have this execution be done by two concurrent threads
First, let's look at what is happening in your code: Each number is printed twice. The reason for this is that i is an instance variable of me, your Thread. So each Thread has its own i, i.e., they do not share the value.
To make the two threads share the same value, we need to pass the same value when constructing me. Now, doing so with the primitive int won't help us much, because by passing an int we are not passing a reference, hence the two threads will still work on independent memory locations.
Let us define a new class, Value which holds the integer for us: (Edit: The same could also be achieved by passing an array int[], which also holds the reference to the memory location of its content)
class Value{
int i = 1;
}
Now, main can instantiate one object of type Value and pass the reference to it to both threads. This way, they can access the same memory location.
class Me extends Thread {
final Value v;
public Me(Value v){
this.v = v;
}
public void run(){
for(; v.i < 50; v.i++){
// ...
}
public static void main(){
Value valueInstance = new Value();
Me a = new Me(valueInstance);
Me b = new Me(valueInstance);
}
}
Now i isn't printed twice each time. However, you'll notice that the behavior is still not as desired. This is because the operations are interleaved: a may read i, let's say, the value is 5. Next, b increments the value of i, and stores the new value. i is now 6. However, a did still read the old value, 5, and will print 5 again, even though b just printed 5.
To solve this, we must lock the instance v, i.e., the object of type Value. Java provides the keyword synchronized, which will hold a lock during the execution of all code inside the synchronized block. However, if you simply put synchronize in your method, you still won't get what you desire. Assuming you write:
public void run(){ synchronized(v) {
for(; v.i < 50; v.i++) {
// ...
}}
Your first thread will acquire the lock, but never release it until the entire loop has been executed (which is when i has the value 50). Hence, you must release the lock somehow when it is safe to do so. Well... the only code in your run method that does not depend on i (and hence does not need to be locking) is sleep, which luckily also is where the thread spends the most time in.
Since everything is in the loop body, a simple synchronized block won't do. We can use Semaphore to acquire a lock. So, we create a Semaphore instance in the main method, and, similar to v, pass it to both threads. We can then acquire and release the lock on the Semaphore to let both threads have the chance to get the resource, while guaranteeing safety.
Here's the code that will do the trick:
public class Me extends Thread {
public int name;
final Value v;
final Semaphore lock;
public Me(Value v, Semaphore lock) {
this.v = v;
this.lock = lock;
}
public void run() {
try {
lock.acquire();
while (v.i <= 50) {
System.out.println("Thread" + name + " : " + v.i);
v.i++;
lock.release();
sleep(100);
lock.acquire();
}
lock.release();
} catch (Exception e) {
System.out.println("some problem");
}
}
public static void main(String[] args) {
Value v = new Value();
Semaphore lock = new Semaphore(1);
Me a = new Me(v, lock);
Me b = new Me(v, lock);
a.name = 1;
b.name = 2;
a.start();
b.start();
}
static class Value {
int i = 1;
}
}
Note: Since we are acquiring the lock at the end of the loop, we must also release it after the loop, or the resource will never be freed. Also, I changed the for-loop to a while loop, because we need to update i before releasing the lock for the first time, or the other thread can again read the same value.
Check the below link for the solution. Using multiple threads we can print the numbers in ascending order
http://cooltekhie.blogspot.in/2017/06/#987628206008590221
I have a single writer thread and single reader thread to update and process a pool of arrays(references stored in map). The ratio of writes to read is almost 5:1(latency of writes is a concern).
The writer thread needs to update few elements of an array in the pool based on some events. The entire write operation(all elements) needs to be atomic.
I want to ensure that reader thread reads the previous updated array if writer thread is updating it(something like volatile but on entire array rather than individual fields). Basically, I can afford to read stale values but not block.
Also, since the writes are so frequent, it would be really expensive to create new objects or lock the entire array while read/write.
Is there a more efficient data structure that could be used or use cheaper locks ?
How about this idea: The writer thread does not mutate the array. It simply queues the updates.
The reader thread, whenever it enters a read session that requires a stable snapshot of the array, applies the queued updates to the array, then reads the array.
class Update
{
int position;
Object value;
}
ArrayBlockingQueue<Update> updates = new ArrayBlockingQueue<>(Integer.MAX_VALUE);
void write()
{
updates.put(new Update(...));
}
Object[] read()
{
Update update;
while((update=updates.poll())!=null)
array[update.position] = update.value;
return array;
}
Is there a more efficient data structure?
Yes, absolutely! They're called persistent data structures. They are able to represent a new version of a vector/map/etc merely by storing the differences with respect to a previous version. All versions are immutable, which makes them appropiate for concurrency (writers don't interfere/block readers, and vice versa).
In order to express change, one stores references to a persistent data structure in a reference type such as AtomicReference, and changes what those references point to - not the structures themselves.
Clojure provides a top-notch implementation of persistent data structures. They're written in pure, efficient Java.
The following program exposes how one would approach your described problem using persistent data structures.
import clojure.lang.IPersistentVector;
import clojure.lang.PersistentVector;
public class AtomicArrayUpdates {
public static Map<Integer, AtomicReference<IPersistentVector>> pool
= new HashMap<>();
public static Random rnd = new Random();
public static final int SIZE = 60000;
// For simulating the reads/writes ratio
public static final int SLEEP_TIMÉ = 5;
static {
for (int i = 0; i < SIZE; i++) {
pool.put(i, new AtomicReference(PersistentVector.EMPTY));
}
}
public static class Writer implements Runnable {
#Override public void run() {
while (true) {
try {
Thread.sleep(SLEEP_TIMÉ);
} catch (InterruptedException e) {}
int index = rnd.nextInt(SIZE);
IPersistentVector vec = pool.get(index).get();
// note how we repeatedly assign vec to a new value
// cons() means "append a value".
vec = vec.cons(rnd.nextInt(SIZE + 1));
// assocN(): "update" at index 0
vec = vec.assocN(0, 42);
// appended values are nonsense, just an example!
vec = vec.cons(rnd.nextInt(SIZE + 1));
pool.get(index).set(vec);
}
}
}
public static class Reader implements Runnable {
#Override public void run() {
while (true) {
try {
Thread.sleep(SLEEP_TIMÉ * 5);
} catch (InterruptedException e) {}
IPersistentVector vec = pool.get(rnd.nextInt(SIZE)).get();
// Now you can do whatever you want with vec.
// nothing can mutate it, and reading it doesn't block writers!
}
}
}
public static void main(String[] args) {
new Thread(new Writer()).start();
new Thread(new Reader()).start();
}
}
Another idea, given that the array contains only 20 doubles.
Have two arrays, one for write, one for read.
Reader locks the read array during read.
read()
lock();
read stuff
unlock();
Writer first modifies the write array, then tryLock the read array, if locking fails, fine, write() returns; if locking succeeds, copy the write array to the read array, then release the lock.
write()
update write array
if tryLock()
copy write array to read array
unlock()
Reader can be blocked, but only for the time it takes to copy the 20 doubles, which is short.
Reader should use spin lock, like do{}while(tryLock()==false); to avoid being suspended.
I would do as follows:
synchronize the whole thing and see if the performance is good enough. Considering you only have one writer thread and one reader thread, contention will be low and this could work well enough
private final Map<Key, double[]> map = new HashMap<> ();
public synchronized void write(Key key, double value, int index) {
double[] array = map.get(key);
array[index] = value;
}
public synchronized double[] read(Key key) {
return map.get(key);
}
if it is too slow, I would have the writer make a copy of the array, change some values and put the new array back to the map. Note that array copies are very fast - typically, a 20 items array would most likely take less than 100 nanoseconds
//If all the keys and arrays are constructed before the writer/reader threads
//start, no need for a ConcurrentMap - otherwise use a ConcurrentMap
private final Map<Key, AtomicReference<double[]>> map = new HashMap<> ();
public void write(Key key, double value, int index) {
AtomicReference<double[]> ref = map.get(key);
double[] oldArray = ref.get();
double[] newArray = oldArray.clone();
newArray[index] = value;
//you might want to check the return value to see if it worked
//or you might just skip the update if another writes was performed
//in the meantime
ref.compareAndSet(oldArray, newArray);
}
public double[] read(Key key) {
return map.get(key).get(); //check for null
}
since the writes are so frequent, it would be really expensive to create new objects or lock the entire array while read/write.
How frequent? Unless there are hundreds of them every millisecond you should be fine.
Also note that:
object creation is fairly cheap in Java (think around 10 CPU cycles = a few nanoseconds)
garbage collection of short lived object is generally free (as long as the object stays in the young generation, if it is unreachable it is not visited by the GC)
whereas long lived objects have a GC performance impact because they need to be copied across to the old generation
The following variation is inspired by both my previous answer and one of zhong.j.yu's.
Writers don't interfere/block readers and vice versa, and there are no thread safety/visibility issues, or delicate reasoning going on.
public class V2 {
static Map<Integer, AtomicReference<Double[]>> commited = new HashMap<>();
static Random rnd = new Random();
static class Writer {
private Map<Integer, Double[]> writeable = new HashMap<>();
void write() {
int i = rnd.nextInt(writeable.size());
// manipulate writeable.get(i)...
commited.get(i).set(writeable.get(i).clone());
}
}
static class Reader{
void read() {
double[] arr = commited.get(rnd.nextInt(commited.size())).get();
// do something useful with arr...
}
}
}
You need two static references: readArray and writeArray and a simple mutex to track when write has been changed.
have a locked function called changeWriteArray make changes to a deepCopy of writeArray:
synchronized String[] changeWriteArray(String[] writeArrayCopy, other params go here){
// here make changes to deepCopy of writeArray
//then return deepCopy
return writeArrayCopy;
}
Notice that changeWriteArray is functional programming with effectively no side effect since it is returning a copy that is neither readArray nor writeArray.
whoever calles changeWriteArray must call it as writeArray = changeWriteArray(writeArray.deepCopy()).
the mutex is changed by both changeWriteArray and updateReadArray but is only checked by updateReadArray. If the mutex is set, updateReadArray will simply point the reference of readArray to the actual block of writeArray
EDIT:
#vemv concerning the answer you mentioned. While the ideas are the same, the difference is significant: the two static references are static so that no time is spent actually copying the changes into the readArray; rather the pointer of readArray is moved to point to writeArray. Effectively we are swapping by means of a tmp array that changeWriteArray generates as necessary. Also the locking here is minimal as reading does not require locking in the sense that you can have more than one reader at any given time.
In fact, with this approach, you can keep a count of concurrent readers and check the counter to be zero for when to update readArray with writeArray; again, furthering that reading requires no lock at all.
Improving on #zhong.j.yu's answer, it is really a good idea to queue the writes instead of trying to perform them when they occur. However, we must tackle the problem when updates are coming so fast that the reader would choke on updates continuously coming in. My idea is what if the reades only performs the writes that were queued before the read, and ignoring subsequent writes (those would be tackled by next read).
You will need to write your own synchornised queue. It will be based off a linked list, and would contain only two methods:
public synchronised enqeue(Write write);
This method will atomically enqueue a write. There is a possible deadlock when writes would come faster than it would actually take to enqueue them, but I think there would have to be hundreds of thousands of writes every second to achieve that.
public synchronised Element cut();
This will atomically empty the queue and returns its head (or tail) as the Element object. It will contain a chain of other Elements (Element.next, etc..., just the usual linked list stuff), all those representing a chain of writes since last read. The queue would then be empty, ready to accept new writes. The reader then can trace the Element chain (which will be standalone by then, untouched by subsequent writes), perform the writes, and finally perform the read. While the reader processes the read, new writes would be enqueued in the queue, but those will be next read's problem.
I wrote this once, albeit in C++, to represent a sound data buffer. There were more writes (driver sends more data), than reads (some mathematical stuff over the data), while the writes had to finish as soon as possible. (The data came in real-time, so I needed to save them before next batch was ready in the driver.)
I've got a funny solution using three arrays and a volatile boolean toggle. Basically, both threads have its own array. Additionally, there's a shared array controlled via the toggle.
When the writer finishes and the toggle allows it, it copies the newly written array into the shared array and flips the toggle.
Similarly, before the reader starts, when the toggle allows it, it copies the shared array into its own array and flips the toggle.
public class MolecularArray {
private final double[] writeArray;
private final double[] sharedArray;
private final double[] readArray;
private volatile boolean writerOwnsShared;
MolecularArray(int length) {
writeArray = new double[length];
sharedArray = new double[length];
readArray = new double[length];
}
void read(Consumer<double[]> reader) {
if (!writerOwnsShared) {
copyFromTo(sharedArray, readArray);
writerOwnsShared = true;
}
reader.accept(readArray);
}
void write(Consumer<double[]> writer) {
writer.accept(writeArray);
if (writerOwnsShared) {
copyFromTo(writeArray, sharedArray);
writerOwnsShared = false;
}
}
private void copyFromTo(double[] from, double[] to) {
System.arraycopy(from, 0, to, 0, from.length);
}
}
It depends on the "single writer thread and single reader" assumption.
It never blocks.
It uses a constant (albeit huge) amount of memory.
Repeated calls to read without any intervening write do no copying and vice versa.
The reader does not necessarily see the most recent data, but it sees the data from the first write started after the previous read, if any.
I guess, this could be improved using two shared arrays.
This piece of code:
synchronized (mList) {
if (mList.size() != 0) {
int s = mList.size() - 1;
for (int i = s; i > 0; i -= OFFSET) {
mList.get(i).doDraw(canv);
}
getHead().drawHead(canv);
}
}
Randomly throws AIOOBEs. From what I've read, the synchronized should prevent that, so what am I doing wrong?
Edits:
AIOOBE = Array Index Out Of Bounds Exception
The code's incomplete, cut down to what is needed. But to make you happy, OFFSET is 4, and just imagine that there is a for-loop adding a bit of data at the beginning. And a second thread reading and / or modifying the list.
Edit 2:
I've noticed it happens when the list is being drawn and the current game ends. The draw-thread hasn't drawn all elements when the list is emptied. Is there a way of telling the game to wait with emtying the list untill it's empty?
Edit 3:
I've just noticed that I'm not sure if this is a multi-threading problem. Seems I only have 2 threads, one for calculating and drawing and one for user input.. Gonna have to look into this a bit more than I thought.
What you're doing looks right... but that's all:
It doesn't matter on what object you synchronize, it needn't be the list itself.
What does matter is if all threads always synchronize on the same object, when accessing a shared resource.
Any access to SWING (or another graphic library) must happen in the AWT-Thread.
To your edit:
I've noticed it happens when the list is being drawn and the current game ends. The draw-thread hasn't drawn all elements when the list is emptied. Is there a way of telling the game to wait with emtying the list untill it's empty?
I think you mean "...wait with emptying the list until the drawing has completed." Just synchronize the code doing it on the same lock (i.e., the list itself in your case).
Again: Any access to a shared resource must be protected somehow. It seems like you're using synchronized just here and not where you're emptying the list.
The safe solution is to only allow one thread to create objects, add and remove them from a List after the game has started.
I had problems myself with random AIOOBEs erros and no synchornize could solve it properly plus it was slowing down the response of the user.
My solution, which is now stable and fast (never had an AIOOBEs since) is to make UI thread inform the game thread to create or manipulate an object by setting a flag and coordinates of the touch into the persistent variables.
Since the game thread loops about 60 times per second this proved to be sufficent to pick up the message from the UI thread and do something.
This is a very simple solution and it works great!
My suggestion is to use a BlockingQueue and I think you are looking for this solution also. How you can do it? It is already shown with an example in the javadoc :)
class Producer implements Runnable {
private final BlockingQueue queue;
Producer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { queue.put(produce()); }
} catch (InterruptedException ex) { ... handle ...}
}
Object produce() { ... }
}
class Consumer implements Runnable {
private final BlockingQueue queue;
Consumer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { consume(queue.take()); }
} catch (InterruptedException ex) { ... handle ...}
}
void consume(Object x) { ... }
}
class Setup {
void main() {
BlockingQueue q = new SomeQueueImplementation();
Producer p = new Producer(q);
Consumer c1 = new Consumer(q);
Consumer c2 = new Consumer(q);
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
}
The beneficial things for you are, you need not to worry about synchronizing your mList. BlockingQueue offers 10 special method. You can check it in the doc. Few from javadoc:
BlockingQueue methods come in four forms, with different ways of handling operations that cannot be satisfied immediately, but may be satisfied at some point in the future: one throws an exception, the second returns a special value (either null or false, depending on the operation), the third blocks the current thread indefinitely until the operation can succeed, and the fourth blocks for only a given maximum time limit before giving up.
To be in safe side: I am not experienced with android. So not certain whether all java packages are allowed in android. But at least it should be :-S, I wish.
You are getting Index out of Bounds Exception because there are 2 threads that operate on the list and are doing it wrongly.
You should have been synchronizing at another level, in such a way that no other thread can iterate through the list while other thread is modifying it! Only on thread at a time should 'work on' the list.
I guess you have the following situation:
//piece of code that adds some item in the list
synchronized(mList){
mList.add(1, drawableElem);
...
}
and
//code that iterates you list(your code simplified)
synchronized (mList) {
if (mList.size() != 0) {
int s = mList.size() - 1;
for (int i = s; i > 0; i -= OFFSET) {
mList.get(i).doDraw(canv);
}
getHead().drawHead(canv);
}
}
Individually the pieces of code look fine. They seam thread-safe. But 2 individual thread-safe pieces of code might not be thread safe at a higher level!
It's just you would have done the following:
Vector v = new Vector();
if(v.length() == 0){ v.length() itself is thread safe!
v.add("elem"); v.add() itself is also thread safe individually!
}
BUT the compound operation is NOT!
Regards,
Tiberiu