I'm trying to add items to a JList asynchronously but I am regularly getting exceptions from another thread, such as:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 8
Does anyone know how to fix this?
(EDIT: I answered this question because it's been bugging me and there is no clear search engine friendly way of finding this info.)
Swing components are NOT thread-safe and may sometimes throw exceptions. JList in particular will throw ArrayIndexOutOfBounds exceptions when clearing and adding elements.
The work-around for this, and the preferred way to run things asynchronously in Swing, is to use the invokeLater method. It ensures that the asynchronous call is done when all other requests.
Example using SwingWorker (which implements Runnable):
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void> () {
#Override
protected Void doInBackground() throws Exception {
Collection<Object> objects = doSomethingIntense();
this.myJList.clear();
for(Object o : objects) {
this.myJList.addElement(o);
}
return null;
}
}
// This WILL THROW EXCEPTIONS because a new thread will start and meddle
// with your JList when Swing is still drawing the component
//
// ExecutorService executor = Executors.newSingleThreadExecutor();
// executor.execute(worker);
// The SwingWorker will be executed when Swing is done doing its stuff.
java.awt.EventQueue.invokeLater(worker);
Of course you don't need to use a SwingWorker as you can just implement a Runnable instead like this:
// This is actually a cool one-liner:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Collection<Object> objects = doSomethingIntense();
this.myJList.clear();
for(Object o : objects) {
this.myJList.addElement(o);
}
}
});
The model interface is not thread safe. You can only modify the model in EDT.
It is not thread safe because it asks the size separately from the contents.
Are you perhaps modifying it from another thread? Could perhaps be modifying it in the same thread during execution of a JList (or related) method that expects the contents to remain the same size.
Related
Got a code with Main Thread and myThread. When some button is pressed in Main Thread myThread.start() is called. onCameraFrame constantly gets and saves color values of frames to ArrayList<Double> rV. In myThread i need sout(rV), do some stuff with it and clean rV every 6 seconds.
I used iterator to do such thing, but still i get java.util.ConcurrentModificationException at sout line in myThread. Note it happens at random time. For example after button was pressed sout might work just fine for 1 sec or for 5 minutes, and then - exception.
My suggestion is that rV is used by myThread and by Main Thread (onCameraFrame) at one time. So it collapses.
Need an advice. Struggling with this for hours.
Here's the code.
public class Camera extends Activity implements CvCameraViewListener2 {
#Override
public void onCreate(Bundle savedInstanceState) {
..
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
..
myThread = new Thread(mRunnable);
myThread.start();
}
..
}
Runnable mRunnable = new Runnable() {
#Override
public void run() {
Thread thisThread = Thread.currentThread();
while (myThread==thisThread) {
try {thisThread.sleep(6000);}
catch ..}
mButton.post(new Runnable() {
#Override
public void run() {
/*logging*/
if (!rV.isEmpty()){
System.out.println("rV"+"("+rV.size()+")={"+rV.toString()+"}");
}
*//*clean data*//*
for (Iterator<Double> it = rV.iterator(); it.hasNext();) {
while(it.hasNext()){
Double t = it.next();
it.remove();
}
}
}
});
}
}
};
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
..
if (condition) {
rV.add(somevalue);
}
return inputFrame.rgba();
}
There are two potential issues here. First: ConcurrentModificationException caused by removing from your ArrayList while iterating over the ArrayList. See this question to resolve this first issue.
The second issue is that the ArrayList is not thread-safe. So, you cannot modify 'rV' while iterating over it without it throwing the exception. Use a thread-safe implementation from the java.util.concurrent package instead. For instance, use an ArrayBlockingQueue. See the tutorial on the Concurrency for more details
#DDsix recommends using a CopyOnWriteArrayList. This may be appropriate in some situations, but inappropriate in others. The JavaDocs for CopyOnWriteArrayList explain it this way:
all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array... This is ordinarily too costly, but may be more efficient than alternatives when traversal operations vastly outnumber mutations, and is useful when you cannot or don't want to synchronize traversals, yet need to preclude interference among concurrent threads.
You have to synchronize the access to the data structure. A good thing to do is to use a Semaphore(java.concurrent package).
Semaphore s = new Semaphore(1); -> 1 permit.
In your thread you aquire the permit: s.aquire() - If there is no permit, the thread stops here. After your work you release the permit: s.release().
And thats it, only one thread can access the data now
You can either use CopyOnWriteArrayList which is basically a thread safe ArrayList, or use Collections.synchronizedList(new ArrayList<Object>()); to create your List (this wouldn't be concurrent, but synchronized, though)
I posted a question yesterday about preventing the UI from freezing when using a scheduledexecutorservice here What should I do in order to prevent the UI from freezing(scheduledexecutorservice) and most people suggested using SwingWorker instead of scheduledexecutorservice. However, I've been stuck since then trying to figure out how a SwingWorker thread would work in my case.
I have the following pseudocode:
createGraph(){
if(rule1)
n = new Node()
graph.add(n)
animateGraph()
createGraph()
if(rule2)
...
I have a recursive algorithm which creates a graph based on certain rules and I want to update the UI when a rule is matched and a new vertex/edge is added to the graph. My question is how can I display the graph whenever a new node/edge is added to it? This should happen in the animateGraph() method and when it hits this method, it should update the actual UI, preferably wait for 1500ms and do that until the whole graph is built.
I tried creating a SwingWorker thread. In this case it doesn't show the intermediate steps of the graph creation but only the final graph. First, it executes all calls to doInBackground() and then it goes to done().
NB: I create a new SwingWorker thread every time a new vertex/edge is created as I read that doInBackground() is only called once.
private void animateGraph() {
swingWorker = createRunnable();
swingWorker.execute();
}
private void displayGraph() {
JPanel.add(graph);
}
private SwingWorker<Object, Object> createRunnable() {
swingWorker = new SwingWorker<Object, Object>() {
#Override
protected Void doInBackground() throws Exception {
System.out.println("Start sleeping.. " + new Date());
Thread.sleep(1500);
publish(new NodeTuple(new Node("A"), new Node("B")));
return null;
}
protected void process(List<NodeTuple> chunks) {
System.out.println("In process.. " + new Date());
NodeTuple nodeTuple = chunks.get(chunks.size() - 1);
graph.addVertex(nodeTuple.source);
graph.addVertex(nodeTuple.target);
checkIfToAddEdge(nodeTuple.source, nodeTuple.target);
createDiagram();
}
}
};
return swingWorker;
}
Edit: I updated doInBackground() and process() methods. However, I still don't get what I really want. No intermediate steps are shown and only the final graph is displayed.
You should probably use the publish/process API of the SwingWorker (see the second example of the SwingWorker API doc for code).
This will allow you create nodes recursively and off the EDT, then publish new nodes matching your rule, before finally processing these nodes on the EDT for display or animation.
Adding animation will need it's own thread, and I suggest you add that as a separate task, but at least you should be able to see new nodes showing up as they are added to the graph.
To see the intermediate steps, you have to publish() each new Node as it's created and process() it on the event dispatch thread, like they show in Tasks that Have Interim Results.
class FlipTask extends SwingWorker<List<Node>, Node> {
#Override
protected List<Node> doInBackground() {
…
publish(new (Node);
…
}
protected void process(List<Node> list) {
// add each new Node to the view
}
}
I've a method who return a result (return an integer), my method is executed in a Thread for load 40 000 objects, i return an integer who count the number objects loaded. My question is, How return the int with the Thread ? Actually, the result is returned directly and is equal to 0.
public int ajouter(params) throws DaoException, ConnectException {
final ProgressDialog dialog = ProgressDialog.show(mActivity, "Title",
"Message", true);
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
dialog.dismiss();
}
};
Thread t = new Thread() {
public void run() {
try {
Str_Requete = "SELECT * FROM Mytable";
ResultSet result = ExecuteQuery(Str_Base, Str_Requete);
Index = addObjects(result);
handler.sendEmptyMessage(0);
} catch (SQLException e) {
e.printStackTrace();
}
}
};
t.start();
return Index;
}
When i call my method in my mainActivity :
int test = myObjs.ajouter(params);
test is equal to 0, the value is returned directly...
My constraint is didnt use AsyncTask.
The whole point of using a Thread is not to block the calling code while performing the task of the thread. Thread.start() returns immediately, but in the meantime a new thread is started in parallel to the current thread which will execute the code in the run() method.
So by definition there is no such thing as returning a value from a thread execution. You have to somehow send a signal back from the thread that performed the task to the thread in which you need the result. There are many ways of doing this, there's the standard Java wait/notify methods, there is the Java concurrency library etc.
Since this is Android, and I assume your calling code is running on the main thread, it's probably wise to use the functionality of Handler. And in fact, you are already doing that - you have a Handler that closes the dialog when the thread is done with its work - but for some reason you seem to expect the result of that work to be ready before it has even started. It would be reasonable to extend your existing Handler with some code that does something with the calculated value and remove the code that returns the value of a variable before or at the same time as it's being calculated by another thread.
I also strongly encourage you to study some concurrency tutorial such as Oracle's concurrency lesson or Android Thread guidelines to really understand what's going on in the background. Writing concurrent code without mastering the concepts is bound to fail sooner or later, because it's in the nature of concurrency that multiple things are happening at the same time, will finish in random order etc. It may not fail often, but you will go crazy wondering why something that works 90% of the time suddenly fails. That's why topics such as atomicity, thread synchronization etc are critical to comprehend.
Edit: Simple Android example of starting a worker thread, performing some work, posting back event to main thread.
public class MyActivity extends Activity {
private Handler mHandler = new Handler();
...
private void doSomeWorkInBackground() {
new Thread() {
public void run() {
// do slow work, this may be blocking
mHandler.post(new Runnable() {
public void run() {
// this code will run on main thread,
// updating your UI or whatever you need.
// Hence, code here must NOT be blocking.
}
});
}
}.start();
// This code will be executed immediately on the main thread, and main thread will not be blocked
}
You could in this example also use Activity.runOnUiThread(Runnable).
Please consider however that AsyncTask basically wraps this kind of functionality in a very convenient way, so if it suits your purposes you should consider using AsyncTask.
If you dont want to use AsyncTask or ForkJoin, then you could implement an Interface e.g. callback in your main class.
In your Example you dont wait until the Thread is done... thread.join
One Solution:
Your Thread is a extra class with an constructor to hold the reference to the calling class.
public Interface callback
{
public int done();
}
public class main implements callback
{
...
CustomThread t = new CustomThread(this)
...
}
public class CustomThread extends Thread
{
private Callback cb;
public CustomThread(Callback cb)
{
this.cb=cb;
}
.
.
.
//when done
cb.done(int)
}
While coding a computation-heavy application, I tried to make use of the SwingWorker class to spread the load to multiple CPU cores. However, behaviour of this class proved to be somewhat strange: only one core seemed to be utilized.
When searching the internet, I found an excellent answer on this web (see Swingworker instances not running concurrently, answer by user268396) which -- in addition to the cause of the problem -- also mentions a possible solution:
What you can do to get around this is use an ExecutorService and post
FutureTasks on it. These will provide 99% of the SwingWorker API
(SwingWorker is a FutureTask derivative), all you have to do is set up
your Executor properly.
Being a Java beginner, I am not entirely sure how to do this properly. Not only that I need to pass some initial data to the FutureTask objects, I also need to get the results back similarly as with SwingWorker. Any example code would therefore be much appreciated.
nvx
==================== EDIT ====================
After implementing the simple yet elegant solution mentioned in FutureTask that implements Callable, another issue has come up. If I use an ExecutorService to create individual threads, how do I execute specific code after a thread finished running?
I tried to override done() of the FutureTask object (see the code below) but I guess that the "show results" bit (or any GUI related stuff for that matter) should be done in the application's event dispatch thread (EDT). Therefore: how do I submit the runnable to the EDT?
package multicoretest;
import java.util.concurrent.*;
public class MultiCoreTest {
static int coresToBeUsed = 4;
static Future[] futures = new Future[coresToBeUsed];
public static void main(String[] args) {
ExecutorService execSvc = Executors.newFixedThreadPool(coresToBeUsed);
for (int i = 0; i < coresToBeUsed; i++) {
futures[i] = execSvc.submit(new Worker(i));
}
execSvc.shutdown();
// I do not want to block the thread (so that users can
// e.g. terminate the computation via GUI)
//execSvc.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
}
static class Worker implements Callable<String> {
private final FutureTask<String> futureTask;
private final int workerIdx;
public Worker(int idx) {
workerIdx = idx;
futureTask = new FutureTask<String>(this) {
#Override
protected void done() {
Runnable r = new Runnable() {
#Override
public void run() {
showResults(workerIdx);
}
};
r.run(); // Does not work => how do I submit the runnable
// to the application's event dispatch thread?
}
};
}
#Override
public String call() throws Exception {
String s = "";
for (int i = 0; i < 2e4; i++) {
s += String.valueOf(i) + " ";
}
return s;
}
final String get() throws InterruptedException, ExecutionException {
return futureTask.get();
}
void showResults(int idx) {
try {
System.out.println("Worker " + idx + ":" +
(String)futures[idx].get());
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
}
A couple of points:
you rarely need to use FutureTask directly, just implement Callable or Runnable and submit the instance to an Executor
in order to update the gui when you are done, as the last step of your run()/call() method, use SwingUtilities.invokeLater() with the code to update the ui.
Note, you can still use SwingWorker, just, instead of calling execute(), submit the SwingWorker to your Executor instead.
if you need to process all results together when all threads are done before updating the gui, then i would suggest:
have each worker stash it's results into a thread-safe, shared list
the last worker to add results to the list should then do the post-processing work
the worker which did the post-processing work should then invoke SwingUtilities.invokeLater() with the final results
I tried to make use of the SwingWorker class to spread the load to
multiple CPU cores. However, behaviour of this class proved to be
somewhat strange: only one core seemed to be utilized.
no idea without posting an SSCCE, short, runnable, compilable,
SSCCE could be based on
SwingWorker is designated creating Workers Thread for Swing GUI, more in this thread
I'm loading contents of a file to JList component. If I do the loading in main thread, everything seems to be OK - contents are loaded. But when I move loading code to separate thread, select an item in a list and try to reload the list, I get random NullPointer or IndexOutOfBounds exceptions. I'm sure this is some kind of Swing threading issue, but can't determine what.
This is my thread code:
#Override
public void run() {
List<String> textLines = null;
textLines = splitter.split(model.getLedMaxChars(), textLoader.loadText(file));
listener.onTextLoaded(textLines);//listener is in main Swing code
}
Controller is responsible for listening:
#Override
public void onTextLoaded(List<String> textLines) {
view.fileLoaded(model.getCurrentFile());
view.setTextLines(textLines);
view.enableListComponent();
}
And the view updates:
public void setTextLines(List<String> textLines) {
jList.setListData(textLines.toArray());
}
I've tried to leave thread to hang by adding while(true); loop - then everything works OK. If I hit reload without selecting item in a list, everything works too.
Could anyone explain what I'm missing here?
Swing components are usually not thread-safe. This means that only the Swing worker thread should do any modifications:
Runnable worker = new Runnable() {
public void run() {
jList.setListData(textLines.toArray());
}
};
SwingUtilities.invokeLater(worker);
See also:
http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html
http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html
Swing is not thread safe, so when you are manipulating GUI elements from other threads many weird things may occur. In your case the simplest solution (but probably not the best) would be to use SwingUtilities.invokeLater