UI issue while using ThreadPoolExecutor - java

I am using ThreadPoolExecutor for implmenting multithreading .
Basically each thread is assigned a file , which needs to be uploaded to the server.
After each successfull upload , a notification is issued from the server.
The following code , generates the thread & assigns the file to them.
Random random = new Random();
ExecutorService executor = new ThreadPoolExecutor(5, 5, 50000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(400));
int waitTime = 100;
while (it.hasNext()) {
int time = random.nextInt(1000);
waitTime += time;
newFile = new File((String) it.next());
executor.execute(new Runnable() {
#Override
public void run() {
processFile(newFile);
}
});
try {
Thread.sleep(waitTime);
} catch (Exception e) {
}
}
try {
Thread.sleep(waitTime);
executor.shutdown();
executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
}
I have created a Java Applet for rendering the UI.
After each notification , I am updating the file status on the Java Applet window where the updateUI() is called from the processFile().
Before using ExecutorService (recommended for handling multithreading on Java v5.0 & above) , I was using a Thread class for creating the threads & wait-notify for the file upload functionality . The UI displaying each file update status gets properly rendered on using the Thread class but on using the ExecutorService , all the files get uploaded(functionality working) but the UI hangs .
After each file is uploaded successfully , the file upload status for each of the files needs to be updated.
Any suggestions/hints welcome.

when wanting to update the UI from a non EDT thread (the event thread that calls the event handlers and such) you need to use SwingUtilities.invokeLater(Runnable)
and you should NEVER sleep on the EDT or block it as that is the one making sure everything is responsive
however it would be better to use a SwingWorker as this implements several things specific to using background threads that need to update the gui
with swingWorker your code will be
while (it.hasNext()) {
final File newFile = new File((String) it.next());
SwingWorker<Void,Void> work = new SwingWorker<Void,Void>(){
#Override
public Void doInBackground() {
processFile(newFile);//do **not** call updateUI() in here
return null;
}
#Override
protected void done(){//this gets called after processFile is done on the EDT
updateUI();
}
}).execute();
}

Related

SWT, multiple threads, and exceptions

I'm using SWT in a main GUI program. Within it, I create another thread to run some programs. However, if some errors are encountered in those processes, I want to report this to the user by making a message box appear. Because in SWT, only a single thread can perform GUI operations, I was having the program runner throw exceptions, so the GUI thread could deal with them. However, I am having problems because I create a new thread for the program runner (in order not to hold up the GUI thread, which will be continuously updating and refreshing some graphics), but as a result, the exceptions that take place are stuck as part of that thread, which can not create the error message box. Any suggestions on how to deal with this?
private void goButtonActionPerformed()
{
// create the program runner object
ProgramRunner PR = new ProgramRunner(); // real code passes in data to be used
try{
// check all necessary parameters are entered
boolean paramsOK = PR.checkParams();
if (paramsOK)
{
// all necessary information is available. Start Processing.
Thread t = new Thread() {
public void run()
{
try{
PR.runPrograms();
}
catch (IOException iox)
{
// This does not work to catch & display the exceptions
// which took place in PR.runPrograms(), because this
// thread is not allowed to perform GUI operations.
// However, I don't know how to pass this
// exception / error notification out of this thread.
MessageBox mb = new MessageBox(m_Shell, SWT.ICON_ERROR);
mb.setMessage(iox.getMessage());
mb.open();
}
}
};
t.start();
}
}
catch (IOException iox)
{
// this works to catch & display the exceptions which took place
// in PR.checkParams() because that is not a separate thread
MessageBox mb = new MessageBox(m_Shell, SWT.ICON_ERROR);
mb.setMessage(iox.getMessage());
mb.open();
}
Wrap catch logic inside a Display.getDefault().asyncExec to display error messages on UI thread:
Thread t = new Thread()
{
public void run()
{
try
{
PR.runProgram();
}
catch ( final IOException iox )
{
Display.getDefault().asyncExec( new Runnable()
{
public void run()
{
MessageBox mb = new MessageBox(m_Shell, SWT.ICON_ERROR);
mb.setMessage(iox.getMessage());
mb.open();
}
});
}
}
});
t.start();
the exceptions can be displayed in UI thread then.
You need to arrange that the UI code runs in the UI thread. You can do this using the asyncExec or syncExec methods of Display.
syncExec suspends the current thread until the UI code has been run. asyncExec does not suspend the thread and runs the UI code as soon as possible.
You can get the current display in any thread using Display.getDefault() so you might do something like:
Display.getDefault().asyncExec(() ->
{
if (m_Shell != null && !m_Shell.isDisposed()) {
MessageBox mb = new MessageBox(m_Shell, SWT.ICON_ERROR);
mb.setMessage(iox.getMessage());
mb.open();
}
});
I have used a Java 8 lambda expression for the Runnable here as it is shorter than the traditional method.
Since this code is being run asynchronously it is good practice to check that the shell is not null and has not been disposed.

libgdx - doing something in other thread not working

My game has a stats queue, after each game the current game stats goes into the queue.
Whenever the mainmenu starts i want to upload all the game stats to a server, and this take like 1-3 seconds and I want to do this in an other thread.
My code
#Override
public void show() {
Global.key = Global.getKey();
// System.out.println(Stats.getJSONObject(Global.key));
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
Stats.TryUploadGame1();
System.out.println("DONE");
}
});
.....
}
But this also freezes my game.
What should I do?
Your current code is posting a Runnable instance that will be executed by the render thread before the next frame. The Gdx.app.postRunnable API is generally used so background threads can ask for something to happen on the render thread. You want to post a Runnable to execute anywhere but the render thread.
As long as your Stats code doesn't interact with OpenGL context at all (since Android OpenGL APIs assume only a single thread interacts with them), you can just post your Runnable on a new background thread:
new Thread(new Runnable() { ... }).start();
This should unblock your render. (Of course, if your background thread uses a lot of CPU, it can still interfere with the render thread, but if its mostly doing blocking IO or host has spare cores, it shouldn't interfere.)
This could be improved in lots of ways (using a ThreadPool, or using Android-aware background task support), but if your stats update is relatively quick and the thread creation isn't frequent this should work fine.
Okay to do something in a other thread you need to take care of the OpenGL context. Inside of a different thread you cant do anything that does render stuff. You are forced to push such thing into the renderthread in any way. And you need to synchronize everything that can be called from the regular render thread from libgdx. For example you want to call the .act(float delta) from a stage from a different thread you are forced to put the stage indo an synchronized block.
The post runable isn't a thread. It is an runable that get executed at the beginning of the next rendercall. So it will stop the game till it's done but it is inside of the OpenGl context thread. (That's why your game stops)
So here is an example of how to use threading in libgdx. I use this inside of my game. It runs on 210 frames so 210 updatecalls per second. You can change it to as fast as possible or just to 60fps whatever you need:
public class GameLogicThread extends Thread {
private GameScreen m_screen;
private boolean m_runing;
private long m_timeBegin;
private long m_timeDiff;
private long m_sleepTime;
private final static float FRAMERATE = 210f;
public GameLogicThread(GameScreen screen) { //pass the game screen to it.
m_screen = screen;
setName("GameLogic");
}
#Override
public void run() {
m_runing = true;
Logger.log("Started");
while (m_runing) {
m_timeBegin = TimeUtils.millis();
// act of the camera
synchronized (m_screen.figureStage) { //stage with figures
// now figures
if (m_screen.m_status == GameStatus.GAME) {
m_screen.figureStage.act(1f / GameLogicThread.FRAMERATE);
}
}
m_timeDiff = TimeUtils.millis() - m_timeBegin;
m_sleepTime = (long) (1f / GameLogicThread.FRAMERATE * 1000f - m_timeDiff);
if (m_sleepTime > 0) {
try {
Thread.sleep(m_sleepTime);
}
catch (InterruptedException e) {
Logger.error("Couldn't sleep " + e.getStackTrace());
}
} else {
Logger.error("we are to slow! " + m_sleepTime); //meight create it dynamic so if you are to slow decrease the framerate till you are not to slow anymore
}
}
}
/**
* Stops the thread save<br>
*/
public void stopThread() {
m_runing = false;
boolean retry = true;
while (retry) {
try {
this.join();
retry = false;
}
catch (Exception e) {
Logger.error(e.getMessage());
}
}
}
}
This does update all my figures. To not cause any troubles with the rendering thread the figurestage is synchronized. (Kind of critical section)
Dont forget that you need to create a new thread every time you stopped it. so for example inside of the show you need todo this:
#Override
public void show() {
super.show();
m_logic = new GameLogicThread(this); //create a new one inside of the GameScreen
m_logic.start(); //start the thread
}
Also dont forget to savestop it inside of the pause stop and so on.
#Override
public void dispose() {
m_logic.stopThread();
}
According to the wiki
To pass data to the rendering thread from another thread we recommend using Application.postRunnable(). This will run the code in the Runnable in the rendering thread in the next frame, before ApplicationListener.render() is called.
So calling that method is just creating a new thread on to run on the render thread.
You may want to use standard java practice on creating threads unless this is frowned upon in libgdx because of android, that I am not sure of.

Java - How to use JProgressBar with SwingWorker

I am creating a Java application with a downloader. My problem is, the progress bar is not working. I want my progress bar to show the download progress but failed. Here is some part of my code. The progressbar just stuck at 0%...
Download.class
public void startDownload()
{
ExecutorService executor = Executors.newSingleThreadExecutor();
FutureTask<Void> verDownloader = new FutureTask<Void>(vd);
FutureTask<Void> launcher = new FutureTask<Void>(dd);
executor.execute(verDownloader);
executor.execute(launcher);
executor.shutdown();
}
VersionDownloader.class
public class VersionDownloader implements Callable<Void>, PropertyChangeListener
{
#Override
public Void call() throws Exception
{
done = false;
final SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>()
{
#Override
protected Void doInBackground() throws Exception
{
try
{
URL fileURL = new URL(url);
org.apache.commons.io.FileUtils.copyURLToFile(fileURL, path);
}
catch(Exception e)
{
}
return null;
}
#Override
public void done()
{
done = true;
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
};
worker.execute();
worker.addPropertyChangeListener(this);
worker.get();
}
}
}
catch(Exception e)
{
}
return null;
}
#Override
public void propertyChange(PropertyChangeEvent evt)
{
if(!done)
{
int progress_a = progress;
//launcher.frame.progress is a JProgressBar
launcher.frame.progress.setValue(progress_a);
}
}
}
Is that any code wrong?
This sort of thing is less trivial than it sounds. copyURLToFile() is going to block until the copy is completed, so that will only give you two events - 0% and 100%.
If you want to show progress while you do the download, there is one prerequisite: You must know the file length before the download starts (so you can compute percentages). You could get that - maybe - by issuing an HTTP HEAD request before starting the copy - but whether the Content-Length field is there in the response depends on the server - for chunked encoding, you don't get this information (though you might be able to force some servers to tell you by issuing an HTTP 1.0 request). Failing that, you could cheat and pick an arbitrary number of bytes.
Once you have the length or an approximation, you can either
Run a timer and periodically check the number of bytes downloaded so far, and compare that with the size, OR
Open the URL as an InputStream and do your own loop to copy the bytes, and on each loop iteration, update the progress bar
Either way, make sure you use EventQueue.invokeLater() to update the progress bar's value property or you may have deadlock issues - it is not safe to modify Swing components from any thread but the event thread.
Read the section from the Swing tutorial on How to Use Progress Bars for a working example that uses a SwingWorker.
Start with something that works and make changes for your particular requirement. If you still have problems then post a SSCCE that demonstrates the problem.

Nothing happens when I call my print method on a thread off the EDT?

I have a method that does some printing and I want the task to run on another thread (not on the EDT) because it might be creating a large file and I dont want the long process to freeze the GUI. The execution works perfectly on the EDT (with GUI freezing of course - which isn't desired), but when invoked on a different thread, it just doesn't execute. Here goes the method;
buildReceipt(itemList, method);
Where;
itemList is an ArrayList used to populate the receipt, and
method is an enum Type that determines whether to make the output a .pdf File or Send it directly to a Printer
The code above produces the document nicely when executed on the EDT but when I tried making it a background task using doInBackground() method of SwingWorker , it just didn't do anything at all; Then I got curious and tried the following;
Thread thread = new Thread(new Runnable(){
#Override
public void run()
{
buildReceipt(itemList, method);
}
});
thread.start();
and still, nothing happened......... More funny and confusing is the fact that I have even tried SwingUtilities.InvokeLater & SwingUtilities.InvokeAndWait (which by documentation run on the EDT) but still to no avail.
I have searched as many Stack Overflow related questions as I could, but none addresses my strange problem. I really need help on this one. Been stuck since yesteray?!?!?!
EDIT:
In Respose to Jean Waghetti; here's briefly what happens inside buildReceipt
private boolean buildReceipt(ArrayList<Sales> itemList, PrintMethod method)
{
boolean built = false;
if(!itemList.isEmpty())
{
InvoiceDesign design = new InvoiceDesign(itemList);
try
{
JasperReportBuilder report = design.build();
if(method.equals(PrintMethod.PDF))
{
appManager.connectToDB();
File fileDir = appManager.getReceiptsDir();
appManager.disconnectDB();
FileOutputStream fos = new FileOutputStream(fileDir);
report.toPdf(fos);
fos.close();
built = true;
}
else if(method.equals(PrintMethod.PRINTER))
{
report.print(true);
built = true;
}
}
catch(IOException e)
{
e.printStackTrace();
}
catch (DRException e)
{
e.printStackTrace();
}
}
return built;
}
So basically your item list is empty hence it never executes the code in the IF condition in that method.

Implementation problems with ThreadPoolExecutor

I am using multiple threads to upload files to the server. The Java Applet is responsible for displaying the UI. Initially I start 5 threads using ThreadPoolExecutor & assign 5 files to them . After each upload, I get a notification from the server. When a thread completes execution , another new thread is assigned with a file until all the files are uploaded to the server.
Basic code structure as follows:
i> a method startUpload() is being called from the Java Applet which is responsible for handling the upload functionality.
class Upload extends Runnable{
...............................
..............................
public void startUpload() {
............................... //other initialisations done
int waitTime = 500;
Random random = new Random();
ExecutorService executor = new ThreadPoolExecutor(5, 5, 50000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(300));
while (it.hasNext()) {
int time = random.nextInt(1000);
waitTime += time;
newFile = new File((String) it.next());
executor.execute(new Runnable() {
#Override
public void run() {
try{
Thread.sleep(wait);
}
catch(Exception e){
}
processFile1(newFile);
}
});
}
try {
Thread.sleep(waitTime);
executor.shutdown();
executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);
} catch (Exception e) {
}
}
}
The problem I am facing currently.
i> The UI is only updating at the end when all the files are upload. In the intermediate stage the UI is in a hanged state. It seems like the EDT is going to a blocked state.
The same code for UI rendering was working fine when I was using Thread class , notify/ sleep to implement the same functionality . I changed the code to ThreadPoolExecutor since I saw in a no of blogs/articles that its a better way of implementing multithreading from Java ver 5.0.
ii> Another thing which I noticed with the ThreadPoolExecutor , when I am uploading multiple files with size 1KB (for testing purpose) , if I remove all the wait() from the above code , the following line assigns a new file but the the same file is always being uploaded everytime by the multiple threads.
newFile = new File((String) it.next());
But on adding sleep() withing the run() , the multiple threads upload different files to the server.
Is there any implementation issue with the above code ?
Problem 1: newFile is a (static?) field instead of a local variable.
What you want is to make sure that the local capture of newFile is different each loop. As such, it should look more like:
while(it.hasNext()) {
final File newFile = new File((String) it.next());
executor.execute(new Runnable() {
#Override
public void run() {
processFile1(newFile); // Local only to this iteration of the loop.
}
}
}
Your code is all wrapped in a Runnable instance. Can you let us know what Thread this is called from? If it's on the EDT then that would explain why the UI locks up.
A small issue is the lack of generics on your iterator. In theory, you should be iterating over a collection of Strings:
Collection<String> listOfFiles = ...
Iterator<String> it = listOfFiles.iterator();
while(it.hasNext()) {
String filename = it.next(); // No cast necessary
}
The UI is hanging because you are blocking the EDT thread. This code is the culprit:
try {
Thread.sleep(waitTime);
executor.shutdown();
executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);
} catch (Exception e) {
}
The idea of an ExecutorService is that you create it one time during initialization and never shut it down until the program is ready to exit. An idiom for this might be:
ExecutorService executor = Executors.newFixedThreadPool(5);
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
executor.shutdown();
}
});
As #Bringer128 mentioned, the second problem is caused by the fact that you are changing the value of a static or member variable and not assigning the File reference to a new location. If the code were correct, we would expect to see the newFile declared as final File newFile because non-final local variables may not be referenced in an inner-class.

Categories