When I run this code, stage shows after task finishing. Why does it happend?
How to make a stage appear before a task?
private List<SensorEntity> detectSensors() throws URISyntaxException {
Task<List<SensorEntity>> task = new TryDetectTask(sensorForDiscover, wifiController);
ProgressIndicator indicator = new ProgressIndicator();
indicator.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);
indicator.progressProperty().bind(task.progressProperty());
Stage stage = new Stage();
stage.setHeight(100);
stage.setWidth(200);
stage.initModality(WINDOW_MODAL);
stage.setScene(new Scene(indicator));
stage.show();
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<List<SensorEntity>> futureTask = executor.submit(task, null);
try {
return futureTask.get(30, SECONDS);
}
catch (InterruptedException | ExecutionException | TimeoutException e) {
log.error(e);
e.printStackTrace();
}
executor.shutdown();
return null;
}
Same result for pane.getScene().setRoot(), alert.show(), Platform.runLater and other, but showAndWait() works fine.
futureTask.get(30, SECONDS) blocks until the result is available or until the 30 seconds have passed. Since you're doing this on the JavaFX application thread any updates to the GUI are blocked during this time.
showAndWait "works" since this call ensures the GUI still updates, but this method only returns when the stage is closed which means you simply freeze the GUI later.
You'd be better off passing a Consumer<List<SensorEntity>> to the method that executes the code using the task result.
private void detectSensors(Consumer<List<SensorEntity>> consumer) throws URISyntaxException {
final boolean[] boolRef = new boolean[1];
Task<List<SensorEntity>> task = new TryDetectTask(sensorForDiscover, wifiController);
task.setOnSucceeded(evt -> {
if (!boolRef[0]) {
boolRef[0] = true;
// submit result unless timeout happened
consumer.accept(task.getValue());
}
});
ProgressIndicator indicator = new ProgressIndicator();
indicator.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);
indicator.progressProperty().bind(task.progressProperty());
Stage stage = new Stage();
stage.setHeight(100);
stage.setWidth(200);
stage.initModality(WINDOW_MODAL);
stage.setScene(new Scene(indicator));
stage.show();
// a thread does not need to be shut down
Thread thread = new Thread(task);
thread.setDaemon(true);
PauseTransition pause = new PauseTransition(Duration.seconds(30));
pause.setOnFinished(evt -> {
if (!boolRef[0]) {
boolRef[0] = true;
// submit null unless task has finished successfully
consumer.accept(null);
}
});
thread.start();
pause.play();
}
Related
I'm trying to use hazelcast ScheduledExecutorService to execute some periodic tasks. I'm using hazelcast 3.8.1.
I start one node and then the other, and the tasks are distributed between both nodes and properly executed.
If I shutdown the first node, then the second one will start to execute the periodic tasks that were previously on the first node.
The problem is that, if I stop the second node instead of the first, then its tasks are not rescheduled to the first one. This happens even if I have more nodes. If I shutdown the last node to receive tasks, those tasks are lost.
The shutdown is always done with ctrl+c
I've created a test application, with some sample code from hazelcast examples and with some pieces of code I've found on the web. I start two instances of this app.
public class MasterMember {
/**
* The constant LOG.
*/
final static Logger logger = LoggerFactory.getLogger(MasterMember.class);
public static void main(String[] args) throws Exception {
Config config = new Config();
config.setProperty("hazelcast.logging.type", "slf4j");
config.getScheduledExecutorConfig("scheduler").
setPoolSize(16).setCapacity(100).setDurability(1);
final HazelcastInstance instance = Hazelcast.newHazelcastInstance(config);
Runtime.getRuntime().addShutdownHook(new Thread() {
HazelcastInstance threadInstance = instance;
#Override
public void run() {
logger.info("Application shutdown");
for (int i = 0; i < 12; i++) {
logger.info("Verifying whether it is safe to close this instance");
boolean isSafe = getResultsForAllInstances(hzi -> {
if (hzi.getLifecycleService().isRunning()) {
return hzi.getPartitionService().forceLocalMemberToBeSafe(10, TimeUnit.SECONDS);
}
return true;
});
if (isSafe) {
logger.info("Verifying whether cluster is safe.");
isSafe = getResultsForAllInstances(hzi -> {
if (hzi.getLifecycleService().isRunning()) {
return hzi.getPartitionService().isClusterSafe();
}
return true;
});
if (isSafe) {
System.out.println("is safe.");
break;
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
threadInstance.shutdown();
}
private boolean getResultsForAllInstances(
Function<HazelcastInstance, Boolean> hazelcastInstanceBooleanFunction) {
return Hazelcast.getAllHazelcastInstances().stream().map(hazelcastInstanceBooleanFunction).reduce(true,
(old, next) -> old && next);
}
});
new Thread(() -> {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
IScheduledExecutorService scheduler = instance.getScheduledExecutorService("scheduler");
scheduler.scheduleAtFixedRate(named("1", new EchoTask("1")), 5, 10, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(named("2", new EchoTask("2")), 5, 10, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(named("3", new EchoTask("3")), 5, 10, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(named("4", new EchoTask("4")), 5, 10, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(named("5", new EchoTask("5")), 5, 10, TimeUnit.SECONDS);
scheduler.scheduleAtFixedRate(named("6", new EchoTask("6")), 5, 10, TimeUnit.SECONDS);
}).start();
new Thread(() -> {
try {
// delays init
Thread.sleep(20000);
while (true) {
IScheduledExecutorService scheduler = instance.getScheduledExecutorService("scheduler");
final Map<Member, List<IScheduledFuture<Object>>> allScheduledFutures =
scheduler.getAllScheduledFutures();
// check if the subscription already exists as a task, if so, stop it
for (final List<IScheduledFuture<Object>> entry : allScheduledFutures.values()) {
for (final IScheduledFuture<Object> objectIScheduledFuture : entry) {
logger.info(
"TaskStats: name {} isDone() {} isCanceled() {} total runs {} delay (sec) {} other statistics {} ",
objectIScheduledFuture.getHandler().getTaskName(), objectIScheduledFuture.isDone(),
objectIScheduledFuture.isCancelled(),
objectIScheduledFuture.getStats().getTotalRuns(),
objectIScheduledFuture.getDelay(TimeUnit.SECONDS),
objectIScheduledFuture.getStats());
}
}
Thread.sleep(15000);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}).start();
while (true) {
Thread.sleep(1000);
}
// Hazelcast.shutdownAll();
}
}
And the task
public class EchoTask implements Runnable, Serializable {
/**
* serialVersionUID
*/
private static final long serialVersionUID = 5505122140975508363L;
final Logger logger = LoggerFactory.getLogger(EchoTask.class);
private final String msg;
public EchoTask(String msg) {
this.msg = msg;
}
#Override
public void run() {
logger.info("--> " + msg);
}
}
I'm I doing something wrong?
Thanks in advance
-- EDIT --
Modified (and updated above) the code to use log instead of system.out. Added logging of task statistics and fixed usage of the Config object.
The logs:
Node1_log
Node2_log
Forgot to mention that I wait until all the task are running in the first node before starting the second one.
Bruno, thanks for reporting this, and it really is a bug. Unfortunately it was not so obvious with multiple nodes as it is with just two. As you figured by your answer its not losing the task, but rather keep it cancelled after a migration. Your fix, however is not safe because a Task can be cancelled and have null Future at the same time, eg. when you cancel the master replica, the backup which never had a future, just gets the result. The fix is very close to what you did, so in the prepareForReplication() when in migrationMode we avoid setting the result. I will push a fix for that shortly, just running a few more tests. This will be available in master and later versions.
I logged an issue with your finding, if you don't mind, https://github.com/hazelcast/hazelcast/issues/10603 you can keep track of its status there.
I was able to do a quick fix for this issue by changing the ScheduledExecutorContainer class of the hazelcast project (used 3.8.1 source code), namely the promoteStash() method. Basically I've added a condition for the case were we task was cancelled on a previous migration of data.
I don't now the possible side effects of this change, or if this is the best way to do it!
void promoteStash() {
for (ScheduledTaskDescriptor descriptor : tasks.values()) {
try {
if (logger.isFinestEnabled()) {
logger.finest("[Partition: " + partitionId + "] " + "Attempt to promote stashed " + descriptor);
}
if (descriptor.shouldSchedule()) {
doSchedule(descriptor);
} else if (descriptor.getTaskResult() != null && descriptor.getTaskResult().isCancelled()
&& descriptor.getScheduledFuture() == null) {
// tasks that were already present in this node, once they get sent back to this node, since they
// have been cancelled when migrating the task to other node, are not rescheduled...
logger.fine("[Partition: " + partitionId + "] " + "Attempt to promote stashed canceled task "
+ descriptor);
descriptor.setTaskResult(null);
doSchedule(descriptor);
}
descriptor.setTaskOwner(true);
} catch (Exception e) {
throw rethrow(e);
}
}
}
I'm trying to do some optimization in my code and would like to spawn a thread where I do a time consuming operation. During the implementation of that optimization I was running into an issue which was driving me crazy. I simplified the issue and created a test case for that specific issue: (I'm using SpringJUnit4ClassRunner so the transaction is properly started at the beginning of the testCRUD method)
Could someone help me understand why the foundParent is null in the thread ?
private Semaphore sema = new Semaphore(0, false);
private long parentId;
#Test
public void testCRUD() {
//create
DBParent parent = null;
{
parent = new DBParent();
parentDao.persist(parent);
parentId = parent.getId();
assertTrue(parentId > 0);
parentDao.flush();
}
(new Thread(
new Runnable() {
public void run()
{
System.out.println("Start adding childs !");
DBParent foundParent = parentDao.findById(parentId);
assertTrue(foundParent != null); //ASSERTION FAILS HERE !!!!
System.out.println("Releasing semaphore !");
sema.release();
System.out.println("End adding childs !");
}
})).start();
try {
System.out.println("Acquiring semaphore !");
sema.acquire();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
=============================EDITED===================================
As per one comment suggestion, I created a threadManager bean which spawn the thread. Here is the code of the threadManager:
public class ThreadManager {
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void executeTask(String Name, Runnable task) {
(new Thread(task, Name)).start();
}
}
Then in the previous test, instead of staring the thread manually, I just post it in the thread manager like this:
#Autowired private ParentDao parentDao;
#Autowired private ThreadManager threadManager;
private Semaphore sema = new Semaphore(0, false);
private long parentId;
#Test
public void testCRUD() {
//create
DBParent parent = null;
{
parent = new DBParent();
parentDao.persist(parent);
parentId = parent.getId();
assertTrue(parentId > 0);
parentDao.flush();
}
threadManager.executeTask("BG processing...",
new Runnable() {
public void run()
{
System.out.println("Start adding childs !");
DBParent foundParent = parentDao.findById(parentId);
assertTrue(foundParent != null); //ASSERTION FAILS HERE !!!!
System.out.println("Releasing semaphore !");
sema.release();
System.out.println("End adding childs !");
}
});
try {
System.out.println("Acquiring semaphore !");
sema.acquire();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
Unfortunately this doesn't work either !!! :-(
The transaction context is bound to the thread. So the code in the spawned thread doesn't run in the same transaction context as the code in the initial thread. So, due to transaction isolation (the I in ACID), the spawned thread doesn't see what the initial thread's transaction is inserting in the database.
You can bind Spring transaction to a new thread, to run transactions & Hibernate/JPA access in it. But this has to be a different TX and JPA/HB session from other threads.
Spring code for OpenSessionInViewFilter, is a reasonable an example of how to bind Hibernate session to Spring's TX management. You can strip this down to fairly minimal code.
See:
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
OpenSessionInViewFilter.doFilterInternal() -- this is where it actually binds it
TransactionSynchronizationManager.bindResource()
TransactionSynchronizationManager.unbindResource()
TransactionSynchronizationManager.getResource()
In one project (IIRC) I wrapped this functionality into a 'ServerThreadHb' class, to setup & save previous thread-bindings on construction -- with a restore() method to be called in a finally block, to restore previous bindings.
For your posted code sample, there isn't much point in running work on a separate thread -- since you synchronously wait for the work to be done. However I assume you were planning to remove that constraint & extend that functionality.
I want to perform some long running operation (e.g. listening to some event raised by OS) on the background thread. Most of the times, operation will run continuously without any problem. But in certain rare conditions, OS level API sends some error code and I need to raise exception from background thread which has to be propagated to the main thread to show it to the user of my WinFrom application.
I had decided to use BackgroundWorker for this. But .NET 4.0 provides Task class of the Task Parallel Library which is a better option as per various blogs on the TPL.
In my application, I have to kick off the background task before actual form is shown. Since actual code is quite complex, I have written some sample code simulating real time problem:
public static Task task;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
ThreadTest tt = new ThreadTest();
task = new Task(() => tt.PerformTask("hi"));
task.Start();
try
{
task.Wait();
}
catch (AggregateException aggregateException)
{
// Handle exception here.
}
Application.Run(new Form1());
}
In this code, I never see the main form simply because background task keeps running without exception and task.Wait() call makes the current thread waiting until background task finishes!
Can I use TPL's Task for such scenarios where main thread should not wait until background task is finished but at the same time, it should get exception details whenever exception is raised from the background task?
In above code, one of the solutions could be to move the task creation code at some later stage. But my question is more academic in this case.
Yes you can. Please see the code below.
The program code is:
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
Task longRunningTask = new Task((state) =>
{
LongRunningWork.DoWork( cancellationTokenSource.Token);
},cancellationTokenSource.Token,TaskCreationOptions.LongRunning);
var newForm = new Form1(cancellationTokenSource);
new Thread((state) =>
{
longRunningTask.Start();
try
{
longRunningTask.Wait();
}
catch (AggregateException exception)
{
Action<Exception> showError = (ex) => MessageBox.Show(state as Form, ex.Message);
var mainForm = state as Form;
if (mainForm != null)
{
mainForm.BeginInvoke(showError, exception.InnerException);
}
}
}).Start(newForm);
Application.Run(newForm);
And the code for the long running task is:
public class LongRunningWork
{
public static void DoWork( CancellationToken cancellationToken)
{
int iterationCount = 0;
//While the
while (!cancellationToken.IsCancellationRequested &&iterationCount <5)
{
//Mimic that we do some long jobs here
Thread.Sleep(1000);
iterationCount++;
//The jobs may throw the exception on the specific condition
if (iterationCount ==5)
{
throw new InvalidOperationException("Invalid action");
}
}
//cancel the task
cancellationToken.ThrowIfCancellationRequested();
}
}
Finally, the code for the Form1 which includes a exit button, whose function is to terminate the program on clicking.
public partial class Form1 : Form
{
private CancellationTokenSource _cancellationTokenSource;
public Form1()
{
InitializeComponent();
}
public Form1(CancellationTokenSource cancellationTokenSource):this()
{
_cancellationTokenSource = cancellationTokenSource;
}
private void exitBtn_Click(object sender, EventArgs e)
{
//Cancel out the task
if (_cancellationTokenSource != null)
{
_cancellationTokenSource.Cancel();
}
//Exit the program
Application.Exit();
}
}
Start your long running operation from the form itself rather than before the form is created. Remember that Application.Run() starts a message loop on the current thread, but that means you can use that message loop to poll your task from the Timer class.
class Form1 : Form
{
private Timer PollingTimer;
private Task BackgroundTask;
public Form1()
{
InitializeComponent();
// Begin the background task.
ThreadTest tt = new ThreadTest();
this.BackgroundTask = new Task(() => tt.PerformTask("hi"));
this.BackgroundTask.Start();
// Monitor the task's status by polling it regularly.
this.PollingTimer = new Timer();
this.PollingTimer.Interval = 1000; // In milliseconds.
this.PollingTimer.Tick += timerCallback;
this.PollingTimer.Start();
}
private timerCallback(object sender, EventArgs e)
{
if (this.BackgroundTask.IsFaulted)
{
// Exception information is in BackgroundTask.Exception.
}
}
}
If you dislike polling (which I do), you'll need to catch the exception from your task and marshall it back to your UI thread. The best way to do that is simply not catch the exception in the task itself and provide a continuation method which will only execute on error.
class Form1 : Form
{
private Task BackgroundTask;
public Form1()
{
InitializeComponent();
// Capture the UI thread context.
// (Note, it may be safer to run this in the Form.Load event than the constructor.
var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
// Begin the background task.
ThreadTest tt = new ThreadTest();
this.BackgroundTask = new Task(() => tt.PerformTask("hi"))
// Schedule a continuation to be executed after the task is completed.
.ContinueWith((t,arg) =>
{
// Exception information is in t.Exception
},null, null,
// Only execute the continuation if the task throws an exception.
TaskContinuationOptions.OnlyOnFaulted,
// Execute the continuation on the UI thread we captured above.
uiContext);
this.BackgroundTask.Start();
}
}
MSDN references for Task.ContinueWith() and TaskScheduler.FromCurrentSynchronizationContext().
And, if you have the luxury of .NET 4.5 with async and await:
class Form1 : Form
{
private Task BackgroundTask;
public Form1()
{
InitializeComponent();
}
private async void Form1_Load(object sender, EventArgs e)
{
ThreadTest tt = new ThreadTest();
try
{
// Move your Task creation and start logic into a method.
await tt.RunAsync();
}
catch (Exception ex)
{
// Really smart compiler writers make sure you're on the right thread
// and everything Just Works(tm).
}
}
}
How can I detect when a Scene or Stage changes size in JavaFX 2.1? I cannot find any EventHandler for this.
There are heightProperty and widthProperty. You can use these properties for binding, or add listeners to them.
public void start(Stage stage) {
Scene scene = new Scene(new Group(), 300, 200);
stage.setScene(scene);
stage.titleProperty().bind(
scene.widthProperty().asString().
concat(" : ").
concat(scene.heightProperty().asString()));
stage.show();
}
Or see next example: https://stackoverflow.com/a/9893911/1054140
A way to perform an action after re-sizing a scene was finished you can do this:
(Note: there maybe better ways to do this, for me it did the job)
final Stage primaryStage = getStage() // get your stage from somewhere
// create a listener
final ChangeListener<Number> listener = new ChangeListener<Number>()
{
final Timer timer = new Timer(); // uses a timer to call your resize method
TimerTask task = null; // task to execute after defined delay
final long delayTime = 200; // delay that has to pass in order to consider an operation done
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, final Number newValue)
{
if (task != null)
{ // there was already a task scheduled from the previous operation ...
task.cancel(); // cancel it, we have a new size to consider
}
task = new TimerTask() // create new task that calls your resize operation
{
#Override
public void run()
{
// here you can place your resize code
System.out.println("resize to " + primaryStage.getWidth() + " " + primaryStage.getHeight());
}
};
// schedule new task
timer.schedule(task, delayTime);
}
};
// finally we have to register the listener
primaryStage.widthProperty().addListener(listener);
primaryStage.heightProperty().addListener(listener);
this is too old and basic but it might help a noob like me
you can add a listener to width and height properties
stage.heightProperty().addListener(e ->{
handle....
});
stage.widthProperty().addListener(e ->{
handle....
});
I have an activity in which I call a service that can take a while to complete and until that service didn't finish, the menu options that are clicked should return an error message like "data not yet ready, please try again soon"
however, I want to give it a couple of seconds to finish before I throw that error and during that time, I want to show a progressdialog on the screen.
here is the code that I have:
if(calculatedValue.equals(NOT_YET_CALCULATED)){
//show progress dialog
ProgressDialog progress = ProgressDialog.show(this, "", getResources().getString(R.string.wait), true);
long timeStarted = System.currentTimeMillis();
while(calculatedValue.equals(NOT_YET_CALCULATED) && System.currentTimeMillis() - timeStarted < 1500){
// wait for at most 1.5 seconds
}
progress.dismiss();
if(calculatedValue.equals(NOT_YET_CALCULATED)){
//if it's still not there, there's probably a problem, show generic alert dialog
AlertDialog dialog = new AlertDialog.Builder(this).create();
dialog.setTitle(R.string.not_yet_calulated_alert_title);
dialog.setMessage(getResources().getString(R.string.not_yet_calulated_alert_message));
dialog.show();
}else{
startActivity(j);
}
}else{
startActivity(j);
}
Let me explain:
I check if the value exists, and if it doesn't I show a progress icon (i'm going for the circle thingy) for 1.5 seconds. If after that time it's still not there, I give up and show an error message.
The problem is that the progress thing does not show up on the screen.
what am I doing wrong?
thanks,
e.
figured it out, should use async task for this, here's the code:
if(calculatedValue.equals(NOT_YET_CALCULATED)){
//show progress dialog
final ProgressDialog progress = ProgressDialog.show(this, "", getResources().getString(R.string.wait), true);
AsyncTask<Void, Void, Boolean> waitForCompletion = new AsyncTask<Void, Void, Boolean>(){
#Override
protected Boolean doInBackground(Void... params) {
long timeStarted = System.currentTimeMillis();
while(calculatedValue.equals(NOT_YET_CALCULATED) && System.currentTimeMillis() - timeStarted < 1500){
// wait for 1.5 ms
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Log.e(TAG, "thread interrupted", e);
}
}
progress.dismiss();
return calculatedValue.equals(NOT_YET_CALCULATED);
};
#Override
protected void onPostExecute(Boolean result) {
if(result == true){
AlertDialog dialog = new AlertDialog.Builder(TodayActivity.this).create();
dialog.setTitle(R.string.not_yet_calulated_alert_title);
dialog.setMessage(getResources().getString(R.string.not_yet_calulated_alert_message));
dialog.show();
}else{
i.putExtra(Constants.AMOUNT, Integer.parseInt(calculatedValue));
startActivity(i);
}
}
};
waitForCompletion.execute(null, null, null);
}else{
i.putExtra(Constants.AMOUNT, Integer.parseInt(calculatedValue));
startActivity(i);
}
What you are making now atleast causes a deadlock.
What I normally do is creating the progressdialog as you are doing now and on the same time start another thread that in this situation waits for 1.5second and stop the progressdialog then.
For example
private Runnable waitforcompletion = new Runnable()
{
#Override
public void run()
{
while(calculatedValue.equals(NOT_YET_CALCULATED) && System.currentTimeMillis() - timeStarted < 1500){
Thread.sleep(10);
}
progress.dismiss();
}
};
And for starting just call the above runnable after creating the progressdialog