Reputation: 39
I have read a lot about having multiple-threads running safely, but I honestly don't know what to do in this situation. I am using API, which I pretty much have to use, this line:
Character interactingMonster = myPlayer().getInteracting();
Unfortunately, I have three separate threads running at the same time, and for some reason I am getting this exception, assuming because I am sharing the resources at the same time:
[ERROR][06/18 09:54:56 AM]: Uncaught exception!
java.lang.ArrayIndexOutOfBoundsException: 32767
at org.api.Players.getLocalPlayer(Players.java:39)
All other problems I had with multiple threads, I have fixed by using thread-safe data types, like AtomicLong and CopyOnWriteArrayList, but in this case, I need some advice. I need to find a way of fixing this, without having to leave-out the perks of using multiple threads.
Any tips?
PS. I don't have access to myPlayer().getInteracting();
it's just API and its class is obfuscated.
Upvotes: 0
Views: 327
Reputation: 11440
Read up on synchronization http://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html
I'm a visual person so heres a fun example of synchronization I like to use that I feel explains how synchronization works. The code essentially consists of 2 different thread types, one synchronized and one not. Each of the thread types prints a string followed by an integer that increments from 0 to 9.
In the output you will see at the start a large print out of foo
and bar
, these messages will only ever appear 1 time next to each other at foo 9
and bar 1
, this is the synchronized thread. The un-synchronized thread is hello
and world
, you will see these messages intermingled all over the place.
Output:
foo 0
foo 1
foo 2
foo 3
foo 4
foo 5
foo 6
foo 7
foo 8
foo 9
bar 0
bar 1
bar 2
bar 3
bar 4
bar 5
bar 6
bar 7
bar 8
bar 9
world 0
hello 0
hello 1
world 1
hello 2
world 2
hello 3
world 3
hello 4
world 4
hello 5
world 5
hello 6
world 6
hello 7
world 7
hello 8
world 8
world 9
hello 9
public class ThreadSynch {
public static void main(String [] args) throws InterruptedException {
Object objectLock = new Object();
Thread synchThread1 = new Thread(new SynchronizedRunnable(objectLock, "foo"));
Thread synchThread2 = new Thread(new SynchronizedRunnable(objectLock, "bar"));
synchThread1.start();
synchThread2.start();
// wait for the 2 threads to finish before we start the next ones
synchThread1.join();
synchThread2.join();
Thread notSynchThread1 = new Thread(new NotSynchronizedRunnable("hello"));
Thread notSynchThread2 = new Thread(new NotSynchronizedRunnable("world"));
notSynchThread1.start();
notSynchThread2.start();
}
private static class SynchronizedRunnable implements Runnable {
private Object lock;
private String value;
public SynchronizedRunnable(Object lock, String value) {
this.lock = lock;
this.value = value;
}
@Override
public void run() {
synchronized (lock) {
for(int i=0;i<10;i++) {
System.out.println(value + " " + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
private static class NotSynchronizedRunnable implements Runnable {
private String value;
public NotSynchronizedRunnable(String value) {
this.value = value;
}
@Override
public void run() {
for(int i=0;i<10;i++) {
System.out.println(value + " " + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Upvotes: 1
Reputation: 321
If the API you're calling is not thread safe (the documentation should tell you, your experience would suggest it's not safe), then you will need to synchronize access to it, so only one thread can call it at a time. If the call is always made within the same method (and not much else happens in there), then you can make the whole method synchronized. Alternatively you can have a synchronized block of code, in which case you must have an object to use, eg:
synchronized (myObject) {
// call to non-thread-safe API
}
and ensure you use the same myObject for all calls to the same api.
This will have performance implications, and means you have to start worrying about potential deadlocks. There are many tutorials out there on java and thread safety, using both 'synchronized' and the more recently added Lock objects.
Upvotes: 2
Reputation: 1779
You could always start by synchronizing that line of code with the target object:
Character interactingMonster;
synchronized (myPlayer){
interactingMonster = myPlayer().getInteracting();
}
Upvotes: 0