Java - ExecutorService Cancelling Overhead - java

I am writing a program that generates images in response to user interaction (panning). For each image I create a task and submit this to a ThreadPool. To make the panning more responsive I create two versions of the image needed, one low resolution one and then a high resolution one. The high resolution image can take more than a second to calculate and if the user is panning a lot I do not want to bog down the processor with calculating old high res images. To manage this I have created an UpdateHandler (this is an inner class) in my program that is supposed to sort this out.
On occation some processes that should have been cancelled slip through. What am I doing wrong, why is this not thread safe? I am not great at multi-threading so any tips are welcome.
Updatehandler:
private class UpdateHandler {
private boolean cancelled = false;
private int number;
private Future<WritableImage> future;
private ChangeListener<Number> listener = new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if(newValue.intValue() > number) {
cancel();
}
}
};
private UpdateHandler() {
number = numberOfUpdaters.get() + 1;
numberOfUpdaters.set(number);
numberOfUpdaters.addListener(listener);
if(number < numberOfUpdaters.get()) {//If the number was increased before the listener was applied.
cancel();
}
updateLowResImage();
int resolution = (int) rightPane.resolutionField.getValue();
if(resolution > lowResolution && !isCancelled()) {
new Thread(new Runnable() {
#Override
public void run() {
EnhancedCallable<WritableImage> task = getImageTask(resolution, resolution);
task.setDescription("Generating " + name);
future = threadPool.submit(task);
if(isCancelled()) {//If cancelled before construction but after check cancel again.
cancel();
}
try {
WritableImage image = future.get();
if(image != null) {
setImage(image);
}
} catch (ExecutionException | InterruptedException | CancellationException e) {
//Do nothing.
} finally {//When we are done cancel to make sure the listener is removed.
cancel();
}
}
}).start();
}
}
/**
* Cancels the future or prevents it from starting. Can be called several times without problems.
*/
private void cancel() {
cancelled = true;
try {
if(!future.isDone() && !future.isCancelled()) {//If Future is still active.
future.cancel(true);
}
if(future.isDone() || future.isCancelled()) {//If Future is not active anymore.
numberOfUpdaters.removeListener(listener);
}
} catch(NullPointerException e) {//If the Future is not yet initialised.
numberOfUpdaters.removeListener(listener);
}
}
private boolean isCancelled() {
return cancelled;
}
}

Related

How to keep progress indicator running in javafx

I want a progress indicator to stop only after completely updating the ui. But it stops after executing last line of code in ui method. The indicator should work as:
1> Start the progress
2> Run the progress until all nodes are added to the scene
3> Stop after completion
The way i update is, i pass BorderPane to the thread and set its center a gridpane, which is the last line of code after which the indicator stops.
And the loginTask, if i start it inside Application Thread the indicator does not spin !
borderpane.setCenter(gpane);
UI method
{
Loading loadBar = new Loading(stage);
Task<Boolean> loginTask= checkCredTask();
loginTask.setOnSucceeded(value -> {
loadBar.hideProgress(); });
loadBar.startTask(loginTask);
(new Thread(loginTask)).start();
}
Progress Bar
public class Loading{
private static Stage stage;
private static ProgressIndicator p;
private static Alert alert;
public Loading(Stage s){
stage=s;
p=new ProgressIndicator();
alert = new Alert(AlertType.NONE);
}
public void startTask(Task<Boolean> cm){
if(p != null){
p.setProgress(-1);
p.progressProperty().unbind();
p.progressProperty().bind(cm.progressProperty());
alert.initOwner(stage);
alert.getDialogPane().setStyle("-fx-background-color:rgba(0,0,0,0);");
alert.getDialogPane().getScene().setFill(Color.TRANSPARENT);
alert.initStyle(StageStyle.TRANSPARENT);
alert.getDialogPane().setContent(p);
alert.show();
}
}
public void hideProgress(){
alert.setResult(ButtonType.CLOSE);
}
}
Task
private Task<Boolean> checkCredTask() {
Task<Boolean> loginTask = new Task<Boolean>() {
#Override
public Boolean call() {
Boolean result = false;
int flag = verifyCredential();
if (flag == 1) {
loadUI();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
result = true;
} else if (flag == 2) {
result = false;
}
return result;
}
};
return loginTask;
}
load UI method
ExecutorService execsrv = Executors.newSingleThreadExecutor();
execsrv.execute(new AdminUI(stage,pane,mb));
execsrv.shutdown();
Your code won't even compile. Task<Boolean> loginTask does not override abstract call() method. Even if you wrap
ExecutorService execsrv = Executors.newSingleThreadExecutor();
execsrv.execute(new AdminUI(stage,pane,mb));
execsrv.shutdown();
in call() method it makes no sense, because you are executing new task inside another task.
Assumig that new AdminUI(stage,pane,mb) is long running process and return boolean you should do it in this way:
Task<Boolean> loginTask = new Task<Boolean>() {
#Override
protected Boolean call() throws Exception {
// Start the UI
AdminUI ui = new AdminUI(stage, pane, mb);
return ui.getBooleanValue();
}
};
EDIT
As I said, you are executing AdminUI task inside loginTask what makes no sense. For now you are waiting only for login task but not for AdminUI task. Login task finishes faster than AdminUI that is why indicator stops to early. Extract AdminUI to another Task. This is pseudo code so you have to do it by your self.
Task<Boolean> loginTask= checkCredTask();
loginTask.setOnSucceeded(value -> {
//****** THIS IS PSEUDO CODE ***********
//start AdminUITask
//AdminUITask.setOnSucceeded(value -> {
//loadBar.hideProgress();
//});
});

Java Robot clicking is going at 70 clicks per second cannot figure out the math / what is going wrong

volatile private boolean mouseDown = false;
private int max = 0;
private int min = 0;
private Robot robot;
public MouseClickListener()
{
try
{
robot = new Robot();
} catch (AWTException e)
{
e.printStackTrace();
}
}
#Override
public void nativeMouseClicked(NativeMouseEvent nativeMouseEvent)
{
}
#Override
public void nativeMousePressed(NativeMouseEvent nativeMouseEvent)
{
if (nativeMouseEvent.getButton() == NativeMouseEvent.BUTTON1)
{
max = Native.get().getFrame().getCps().getValue() + Native.get().getFrame().getDev().getValue();
min = Native.get().getFrame().getCps().getValue() - Native.get().getFrame().getDev().getValue();
mouseDown = true;
initThread();
}
}
#Override
public void nativeMouseReleased(NativeMouseEvent nativeMouseEvent)
{
if (nativeMouseEvent.getButton() == NativeMouseEvent.BUTTON1)
{
mouseDown = false;
}
}
Hi there, so basically I'm trying to make an auto clicker which clicks at values to a JSlider (a random value between say 9 and 13, just for example).
So on mouse click the initThread method is called, and the clicks per second is worked out ( a random number between the JSlider value, which is from a diff. class), and then from that, I click and then sleep the thread for 1 / randomNum (in seconds) so that it clicks that many times per second.
For some reason it's clicking at like 200cps and lagging my computer out. Does anyone see any problem with my code?
Thanks.
NEW CODE FOR CLICKER;
public class ClickMethod implements Runnable
{
#Override
public void run()
{
System.out.println("STARTED");
do
{
System.out.println("RUNNING");
Random r = new Random();
int random = r.nextInt((max - min) + 1) + min;
robot.mousePress(BUTTON1_MASK);
robot.mouseRelease(BUTTON1_MASK);
try
{
Thread.sleep(1000 / random);
} catch (InterruptedException e)
{
e.printStackTrace();
}
} while (mouseDown);
}
}
For some reason this only runs once and then isn't called when the mouseDown variable changes.
If this is intended to be clicked by you every so often then it creates numerous threads which all click away
public void nativeMousePressed(NativeMouseEvent nativeMouseEvent)
{
if (nativeMouseEvent.getButton() == NativeMouseEvent.BUTTON1)
{
max = Native.get().getFrame().getCps().getValue() + Native.get().getFrame().getDev().getValue();
min = Native.get().getFrame().getCps().getValue() - Native.get().getFrame().getDev().getValue();
mouseDown = true;
initThread();
}
}
You need to remove initThread() from there and call it once somewhere , e.g., in the constructor.

javaFX - creating smooth animation without creating a new Thread

I have a car in my javaFX project where the position of the car(Node) should change(the car should jump smoothly) when SPACE is pressed . so I have used an event handler which invokes a method named :moveUp()
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode())
{
case SPACE:
moveUp();
break;
}
}
});
This creates a new Thread where the speed of the car is changed 10 times with an interval of 75 milliseconds.
private void moveUp() {
new Thread(new Runnable() {
#Override
public void run() {
carSpeed = 10;
for(;carSpeed>=0;carSpeed--)
{
try {
Thread.currentThread().sleep(75);
} catch (InterruptedException e) {
e.printStackTrace();
}
carPosition_X+=carSpeed;
carPosition_Y-=carSpeed;
car.relocate(carPosition_X,carPosition_Y);
}
for(carSpeed=0;carSpeed<=10;carSpeed++)
{
try {
Thread.currentThread().sleep(75);
} catch (InterruptedException e) {
e.printStackTrace();
}
carPosition_X+=carSpeed;
carPosition_Y+=carSpeed;
car.relocate(carPosition_X,carPosition_Y);
}
}
}).start();
}
This code is doing like this (pressing SPACE once and jumping the car):
If I don't use a different thread the GUI thread will be freeze and if I don't use Thread.sleep() the car will jump abruptly(not smoothly). This code is doing well . But I have learnt that thread.start() doesn't guarantee immediate execution of the thread. How can I guarantee immediate execution ?
I would suggest to stay in the FX Application Thread and to use the class AnimationTimer. Here is a short demo for a smooth jump:
private void moveUp() {
new AnimationTimer() {
long startTime = -1;
double initCarPosition_Y;
#Override
public void handle(long now) {
if(startTime == -1){
startTime = now;
initCarPosition_Y = carPosition_Y;
carSpeedX = 3d;
carSpeedY = -15d;
}
double time = (now - startTime) / 1E9d;
carPosition_X += carSpeedX * time;
carPosition_Y += carSpeedY * time;
if(carSpeed > 0 && initCarPosition_Y <= carPosition_Y){
carPosition_Y = initCarPosition_Y;
stop();
}
carSpeedY += 0.8d * time; //gravity
car.relocate(carPosition_X, carPosition_Y);
}
}.start();
}
This approach gives you full and direct control over what happens in every single frame. However, javaFX also provides high level animation classes including predefined interpolators and transitions. Suitable for alternative approaches could be the following classes:
PathTransition: Allows you to define points and curves which a given node is animated along.
TimeLine: Allows you to define arbitrary animation key frames based on properties like the position of a node.
Note that generally working with these high level classes could become challenging when you want to animate an user controlled actor like your car. These classes all take an exact duration for the animation to last. For example when you want to translate a node as long as a specific key is pressed, you don't know the duration of the animation in beforehand.

How to use JButtons to Start and Pause SwingWorker thread

I'm trying to learn Threads in Swing.
I have a Frame with a JProgressBar (progress), five JButtons (Start, Suspend, Resume, Cancel, Close), and a JLabel (label1).
The frame opens. Only Start is enabled. Start calls my class Progressor:
Updated Again Once and For All
Progressor progressor; //declared as class variable, initialized new in constructor and again in overridden done method
Here's the ButtonListener class:
public class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == jbStart) {
progressor.execute();
label1.setText("Progressing ...");
jbCancel.setEnabled(true);
jbResume.setEnabled(true);
jbSuspend.setEnabled(true);
jbClose.setEnabled(true);
}
if(e.getSource() == jbCancel) {
progressor.cancel(true);
label1.setText("Progress Canceled");
}
if (e.getSource() == jbSuspend) {
label1.setText(progressor.suspendProgress());
}
if (e.getSource() == jbResume) {
label1.setText(progressor.resumeProgress());
}
if (e.getSource() == jbClose) {
dispose();
}
}
}//buttonlistener
Here's the SwingWorker class:
public class Progressor extends SwingWorker<Void, Integer> {
private volatile boolean suspend = false;
private Object lock = new Object();
#Override
protected Void doInBackground() {
for (int i = 0; i <= 10; i++) {
checkForSuspend();
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
}
publish(i);
}
return null;
}
#Override
protected void process(List<Integer> list) {
int value = list.get(list.size() - 1);
progress.setValue(value);
}
public void checkForSuspend() {
synchronized (lock) {
while (suspend) {
try {
lock.wait();
} catch (InterruptedException ie){
}
}
}
}//checkForSuspend
#Override
protected void done() {
label1.setText("All Done. Press close to exit");
progressor = new Progressor();
}
public synchronized String suspendProgress() {
suspend = true;
return "Progress suspended ...";
}
public synchronized String resumeProgress() {
synchronized (lock) {
suspend = false;
lock.notify();
return "Progress resumed ...";
}
}
}//Progressor class
Everything works except the cancel doesn't doesn't actually cancel the thread (the progress bar continues).
Should I suspend it before canceling?
This How to Pause and Resume a Thread in Java from another Thread question looks very similar to yours and has some nice examples in the answers.
As for your own code and why it does not work:
You create a new progressor on every click. You should be using and controlling one, instead of creating new ones every time.
When suspending your progressor finishes work instead of suspending. As the above question states - you should be looking at the flag at some points of your computation and acting on it. Example:
while (!cancel) {
if (!suspended) {
for (int i = 1; i <= 10; i++) {
Thread.sleep(1000);
publish(i);
}
}
}
The above code will suspend when it next reaches 10 (unless you resumed it before that), and finish when you press cancel (Cancel needs to be added as an extra flag in the obvious manner).
Your thread should run inside a while loop that looks for a boolean to change value from another object, then simply change the state with setPause(true/false) when you click the button:
while(true){
if(object_everyone_can_reference.getPause()){
Thread.sleep(1000);
}
}

How to make a checkbox do a continuous task, until it gets unchecked?

Anyone have any idea how to make check box do a task until it gets unchecked?
JCheckBox chckbxInspecAuto = new JCheckBox("Inspe. Auto.");
chckbxInspecAuto.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0)
{
try {
gimage = vision.grab();
cvSaveImage("image001.bmp", gimage);
ipanel.loadImage("image001.bmp");
} catch (com.googlecode.javacv.FrameGrabber.Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
EDIT: The code is over there now...
You could extend the SwingWorker class or even Thread to implement the functionality you want the checkbox to control. Create methods contiueWorking() and stopWorking() and in the run method check some boolean flag to see whether to do the task or sleep.
As Robin commented on a post below, swing components should only be accessed from the Event Worker Thread. I violated this rule in my example below because I wanted to produce something simple and since the running thread spends most of its time sleeping, it works fine.
I would use SwingWorker for a more time consuming task that I wish to update the user on as it executes. For instance, say we have a thread generate and then send a set of email messages, and for each e-mail, display some text in the UI that confirms the message was sent or indicates why it was undeliverable. Each message may lock the Thread up for a while. The UI will not be updated in sync with the Thread's execution of the e-mail task. SwingWorker to the rescue. The java2s.com site has a SwingWokerDemo.
import java.awt.BorderLayout;
import javax.swing.*;
import java.awt.event.*;
import java.util.ArrayList;
/**
* The sequence of prime integers is calculated and displayed on the screen.
* This little program demonstrates how a checkbox can be used
* to start and stop a thread.
*/
public class ThreadDemo extends JFrame {
JCheckBox runningCB;
JTextArea displayArea;
JTextField delayField;
PrimeCalcThread workerThread = null;
public ThreadDemo() {
super("Prime Numbers");
runningCB = new JCheckBox("Calculate Primes");
JPanel topPanel = new JPanel();
topPanel.add(runningCB);
topPanel.add(new JLabel("Dealy: "));
delayField = new JTextField(10);
delayField.setText("500");
topPanel.add(delayField);
getContentPane().add(topPanel,BorderLayout.NORTH);
displayArea = new JTextArea(30,80);
displayArea.setText("2, 3, 5, ");
displayArea.setLineWrap(true);
JScrollPane scroller = new JScrollPane(displayArea);
getContentPane().add(scroller,BorderLayout.CENTER);
pack();
runningCB.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(runningCB.isSelected() ) {
if(workerThread != null)
workerThread.contiueWorking();
else {
workerThread = new PrimeCalcThread();
workerThread.start();
}
}
else {
if(workerThread != null)
workerThread.stopWorking();
}
}
});
delayField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String input = delayField.getText().trim();
try {
int d = Integer.parseInt(input);
workerThread.setDelay(d);
}
catch(NumberFormatException nfe) { }
}
});
setVisible(true);
}
public static void main(String[] arg) {
ThreadDemo window = new ThreadDemo();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
/**
* When this thread is active it calculates prime numbers. The Thread
* continues until it is paused with stopWorking() or until the
* boolean field endThread is set to true.
*/
class PrimeCalcThread extends Thread {
ArrayList<Integer> primeList;
int delay = 500;
boolean active = true;
boolean endThread = false;
private int lastPrime;
public PrimeCalcThread() {
primeList = new ArrayList<> (1024);
primeList.add(2); primeList.add(3); primeList.add(5);
lastPrime=5;
}
public void run() {
while(!endThread) {
if(active) {
calcNextPrime();
displayArea.append(lastPrime + ", ");
}
try { sleep(delay); }
catch(InterruptedException whatever) { }
}
}
private void calcNextPrime() {
int p = lastPrime+2;
while(!isPrime(p))
p+=2;
primeList.add(p);
lastPrime = p;
}
/**
* Checks if p is prime by checking for divisibility by all primes in the
* calculated primeList so far. This method only works if sqrt(p) < lastPrime
*/
private boolean isPrime(int p) {
int maxCheck = (int) Math.sqrt(p) + 1;
for(int prime: primeList) {
if(p % prime == 0)
return false;
if(prime > maxCheck)
break;
}
return true;
}
public int getLastPrime() {
return lastPrime;
}
public ArrayList<Integer> getPrimeList() {
return primeList;
}
public int getDelay() {
return delay;
}
public void setDelay(int waitTime) {
if(waitTime>=0)
delay = waitTime;
}
public void contiueWorking() {
active=true;
}
public void stopWorking() {
active=false;
}
}
}
- Well create a Daemon Thread and run it in an infinite loop, let it keep checking whether the JCheckBox is checked or not using isSelected() method or ItemListener.
- And when the JCheckBox gets selected then create a Thread to execute the task, or use SwingWorker Class which properly synchronizes the UI and Non-UI thread's work.
It depends on the task.
If a task is on other process on other machine you could simply send the right messages.
If the task is a separated thread in the same application you could do what wxyz suggests or you could use some kind of Listener with the ability of start and stop the Thread (the thread is always the same or you are creating a new one every time you select the checkbox?).
My favorite one would be to use Observer pattern in the "PUSH" way, so you would use some kind of external signal to the thread which when sent would create and/or stop it.

Categories

Resources