I'm writing a small programm where JavaFx acts as a viewer and controler and let Java do the other hard work. I can start multiple threads from Javafx however, I'm not able to stop them. If I try to use .stop(), the threads are still running.
Here is one of them:
public var sleepTask_connect;
function LogOutAction(): Void {
sleepTask_connect.stop();
}
function LogInAction(): Void {
var listener = FXListener_interface_connection {
override function callback(errorCode, errorMessage): Void {
//do something
if(errorCode != 200){
setIcn(errorMessage);
}
}
}
sleepTask_connect = FXListener_connection {
listener: listener
};
sleepTask_connect.start();
}
Use JavaTaskBase to implement you Java thread. There is a stop method to kill the thread. Here is an example of how you use it.
I've had better luck with the JFXtras XWorker component for threading. See http://jfxtras.googlecode.com/svn/site/javadoc/release-0.6/org.jfxtras.async/org.jfxtras.async.XWorker.html.
However in general in order for your thread to respond to cancel/stop requests, you have to check the canceled or stopped flag in your code during your "do something" section. This works if your thread is in an infinite loop for example, or if you just have a series of long running processes you can check for canceled/stopped in between them. Alternatively, if your code calls some blocking method (like sockets or a blocking queue), then most of these will throw an InterruptedException when the thread is canceled.
Related
In my Android application I have code that should run periodically in its own coroutine and should be cancelable.
for this I have the following functions:
startJob(): Initializes the job, sets up invokeOnCompletion() and starts the work loop in the respective scope
private fun startJob() {
if (::myJob.isInitialized && myJob.isActive) {
return
}
myJob= Job()
myJob.invokeOnCompletion {
it?.message.let {
var msg = it
if (msg.isNullOrBlank()) {
msg = "Job stopped. Reason unknown"
}
myJobCompleted(msg)
}
}
CoroutineScope(Dispatchers.IO + myJob).launch {
workloop()
}
}
workloop(): The main work loop. Do some work in a loop with a set delay in each iteration:
private suspend fun workloop() {
while (true) {
// doing some stuff here
delay(setDelayInMilliseconds)
}
}
myJobCompleted: do some finalizing. For now simply log a message for testing.
private fun myJobCompleted(msg: String) {
try {
mainActivityReference.logToGUI(msg)
}
catch (e:Exception){
println("debug: " + e.message)
}
}
Running this and calling myJob.Cancel() will throw the following exception in myJobCompleted():
debug: Only the original thread that created a view hierarchy can touch its views.
I'm curious as to why this code isn't running on the main thread, since startJob() IS called from the main thread?
Furthermore: is there a option similar to using a CancellationTokenSource in c#, where the job is not immediately cancelled, but a cancellation request can be checked each iteration of the while loop?
Immediately breaking off the job, regardless of what it is doing (although it will pretty much always be waiting for the delay on cancellation) doesn't seem like a good idea to me.
It is not the contract of Job.invokeOnCompletion to run on the same thread where Job is created. Moreover, such a contract would be impossible to implement.
You can't expect an arbitrary piece of code to run on an arbitrary thread, just because there was some earlier method invocation on that thread. The ability of the Android main GUI thread to execute code submitted from the outside is special, and involves the existence a top-level event loop.
In the world of coroutines, what controls thread assignment is the coroutine context, while clearly you are outside of any context when creating the job. So the way to fix it is to explicitly launch(Dispatchers.Main) a coroutine from within invokeOnCompletion.
About you question on cancellation, you can use withContext(NonCancellable) to surround the part of code you want to protect from cancellation.
I was trying to update the recycler view content from a background thread in Kotlin. I am not using AsyncTask.
Here is my code, i want to know if there is any better way than this:
In my MainActivity, i have progressThread as a member variable.
var progressThread = Thread()
Then in my method where i want to run the thread first i am defining it...like
progressThread = Thread (
Runnable {
kotlin.run {
try {
while (i <= 100 && !progressThread.isInterrupted) {
Thread.sleep(200)
//Some Logic
runOnUiThread {
//this runs in ui thread
}
i++
}
}catch (e:InterruptedException){
progressThread.interrupt()
}
}
})
after that i am starting it in the same method as
progressThread.start()
and for stopping it, i have a listener to cancel the progress and in the callback of that listener, i have written:
progressThread.interrupt()
Updated
Coroutines are stable now,: https://kotlinlang.org/docs/reference/coroutines-overview.html
Old Answer
Yes, you can do this using doAsync from kotlin anko library that is fairly simple and easy to use.
add following line in module level gradle file:
compile "org.jetbrains.anko:anko-commons:0.10.0"
Code example:
val future = doAsync {
// do your background thread task
result = someTask()
uiThread {
// use result here if you want to update ui
updateUI(result)
}
}
code block written in uiThread will only be executed if your Activity or Fragment is in foreground mode (It is lifecycle aware). So if you are trying to stop thread because you don't want your ui code to execute when Activity is in background, then this is an ideal case for you.
As you can check doAsync returns a Future object so you can cancel the background task, by cancel() function:
future.cancel(true)
pass true if you want to stop the thread even when it has started executing.
If you have more specialised case to handle stopping case then you can do the same thing as in your example.
You can use Kotlin Coroutines also but its in Experimental phase, still you can try it out: https://kotlinlang.org/docs/reference/coroutines.html
I would like to create a custom FunctionPlotter component that is based on the JavaFx WebEngine. My plots will be shown in a browser. Before I execute my plot commands I have to wait until the browser has been initialized (it loads d3.js). Currently I do so by putting my plot expressions in a Runnable and pass that runnable to the FunctionPlotter. (The FunctionPlotter passes the runnable to the loading finished hook of the browser):
private FunctionPlotter plotter;
...
Runnable plotRunnable = ()->{
plotter.plot("x^2");
}
plotter = new FunctionPlotter(plotRunnable);
However I would prefer following (blocking) work flow for the usage of my FunctionPlotter component:
Functionplotter plotter = new FunctionPlotter();
plotter.plot("x^2")
=> The FunctionPlotter should automatically wait until the wrapped browser has been initialized.
How should I do this in an JavaFx Application?
Inside the FunctionPlotter I could do something like
private Boolean isInitialized = false
...
ReadOnlyObjectProperty<State> state = webEngine.getLoadWorker().stateProperty();
state.addListener((obs, oldState, newState) -> {
boolean isSucceeded = (newState == Worker.State.SUCCEEDED);
if (isSucceeded) {
isInitialized = true;
}
});
webEngine.loadContent(initialBrowserContent);
waitUntilInitialLoadingIsFinished();
My actual question is how the method on the last line could be implemented. If I use following code, the application will wait for ever:
private void waitUntilBrowserIsInitialized() {
while(!isInitialized){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
I know that there is stuff like JavaFx Tasks, Platform.runLater(), Service, CountdownLatch (JavaFX working with threads and GUI) but those did not help me (= I did not get it working). How can I wait in the main Thread until a Runnable is finished?
Here someone says that the JavaFx Application thread should never be blocked:
Make JavaFX application thread wait for another Thread to finish
Any other suggestions?
Edit
Related question: JavaFX/SWT WebView synchronous loadcontent()
I decided to wrap the plot functionality in an internal queue of plot instructions. The command
plotter.plot("x^2");
will not actually execute the plot but add a plot instruction to the queue. After the browser has been initialized, that queue will be worked through and the plot commands will be executed with a delay. While the browser is initializing I will show some kind of progress bar.
If you know a solution that does not need this delayed execution work around please let me know.
Consider this code :
Thread thread = new Thread(() -> tasks.parallelStream().forEach(Runnable::run));
tasks are a list of Runnables that should be executed in parallel.
When we start this thread, and it begins its execution, then depending on some calculations we need to interrupt (cancel) all those tasks.
Interrupting the Thread will only stop one of exections. How do we handle others? or maybe Streams should not be used that way? or you know a better solution?
You can use a ForkJoinPool to interrupt the threads:
#Test
public void testInterruptParallelStream() throws Exception {
final AtomicReference<InterruptedException> exc = new AtomicReference<>();
final ForkJoinPool forkJoinPool = new ForkJoinPool(4);
// use the pool with a parallel stream to execute some tasks
forkJoinPool.submit(() -> {
Stream.generate(Object::new).parallel().forEach(obj -> {
synchronized (obj) {
try {
// task that is blocking
obj.wait();
} catch (final InterruptedException e) {
exc.set(e);
}
}
});
});
// wait until the stream got started
Threads.sleep(500);
// now we want to interrupt the task execution
forkJoinPool.shutdownNow();
// wait for the interrupt to occur
Threads.sleep(500);
// check that we really got an interruption in the parallel stream threads
assertTrue(exc.get() instanceof InterruptedException);
}
The worker threads do really get interrupted, terminating a blocking operation. You can also call shutdown() within the Consumer.
Note that those sleeps might not be tweaked for a proper unit test, you might have better ideas to just wait as necessary. But it is enough to show that it is working.
You aren't actually running the Runnables on the Thread you are creating. You are running a thread which will submit to a pool, so:
Thread thread = new Thread(() -> tasks.parallelStream().forEach(Runnable::run));
In this example you are in lesser terms doing
List<Runnable> tasks = ...;
Thread thread = new Thread(new Runnable(){
public void run(){
for(Runnable r : tasks){
ForkJoinPool.commonPool().submit(r);
}
}
});
This is because you are using a parallelStream that delegates to a common pool when handling parallel executions.
As far as I know, you cannot get a handle of the Threads that are executing your tasks with a parallelStream so may be out of luck. You can always do tricky stuff to get the thread but probably isn't the best idea to do so.
Something like the following should work for you:
AtomicBoolean shouldCancel = new AtomicBoolean();
...
tasks.parallelStream().allMatch(task->{
task.run();
return !shouldCancel.get();
});
The documentation for the method allMatch specifically says that it "may not evaluate the predicate on all elements if not necessary for determining the result." So if the predicate doesn't match when you want to cancel, then it doesn't need to evaluate any more. Additionally, you can check the return result to see if the loop was cancelled or not.
I'm implementing my own logging framework. Following is my BaseLogger which receives the log entries and push it to the actual Logger which implements the abstract Log method.
I use the C# TPL for logging in an Async manner. I use Threads instead of TPL. (TPL task doesn't hold a real thread. So if all threads of the application end, tasks will stop as well, which will cause all 'waiting' log entries to be lost.)
public abstract class BaseLogger
{
// ... Omitted properties constructor .etc. ... //
public virtual void AddLogEntry(LogEntry entry)
{
if (!AsyncSupported)
{
// the underlying logger doesn't support Async.
// Simply call the log method and return.
Log(entry);
return;
}
// Logger supports Async.
LogAsync(entry);
}
private void LogAsync(LogEntry entry)
{
lock (LogQueueSyncRoot) // Make sure we ave a lock before accessing the queue.
{
LogQueue.Enqueue(entry);
}
if (LogThread == null || LogThread.ThreadState == ThreadState.Stopped)
{ // either the thread is completed, or this is the first time we're logging to this logger.
LogTask = new new Thread(new ThreadStart(() =>
{
while (true)
{
LogEntry logEntry;
lock (LogQueueSyncRoot)
{
if (LogQueue.Count > 0)
{
logEntry = LogQueue.Dequeue();
}
else
{
break;
// is it possible for a message to be added,
// right after the break and I leanve the lock {} but
// before I exit the loop and task gets 'completed' ??
}
}
Log(logEntry);
}
}));
LogThread.Start();
}
}
// Actual logger implimentations will impliment this method.
protected abstract void Log(LogEntry entry);
}
Note that AddLogEntry can be called from multiple threads at the same time.
My question is, is it possible for this implementation to lose log entries ?
I'm worried that, is it possible to add a log entry to the queue, right after my thread exists the loop with the break statement and exits the lock block, and which is in the else clause, and the thread is still in the 'Running' state.
I do realize that, because I'm using a queue, even if I miss an entry, the next request to log, will push the missed entry as well. But this is not acceptable, specially if this happens for the last log entry of the application.
Also, please let me know whether and how I can implement the same, but using the new C# 5.0 async and await keywords with a cleaner code. I don't mind requiring .NET 4.5.
Thanks in Advance.
While you could likely get this to work, in my experience, I'd recommend, if possible, use an existing logging framework :) For instance, there are various options for async logging/appenders with log4net, such as this async appender wrapper thingy.
Otherwise, IMHO since you're going to be blocking a threadpool thread during your logging operation anyway, I would instead just start a dedicated thread for your logging. You seem to be kind-of going for that approach already, just via Task so that you'd not hold a threadpool thread when nothing is logging. However, the simplification in implementation I think benefits just having the dedicated thread.
Once you have a dedicated logging thread, you then only need have an intermediate ConcurrentQueue. At that point, your log method just adds to the queue and your dedicated logging thread just does that while loop you already have. You can wrap with BlockingCollection if you need blocking/bounded behavior.
By having the dedicated thread as the only thing that writes, it eliminates any possibility of having multiple threads/tasks pulling off queue entries and trying to write log entries at the same time (painful race condition). Since the log method is now just adding to a collection, it doesn't need to be async and you don't need to deal with the TPL at all, making it simpler and easier to reason about (and hopefully in the category of 'obviously correct' or thereabouts :)
This 'dedicated logging thread' approach is what I believe the log4net appender I linked to does as well, FWIW, in case that helps serve as an example.
I see two race conditions off the top of my head:
You can spin up more than one Thread if multiple threads call AddLogEntry. This won't cause lost events but is inefficient.
Yes, an event can be queued while the Thread is exiting, and in that case it would be "lost".
Also, there's a serious performance issue here: unless you're logging constantly (thousands of times a second), you're going to be spinning up a new Thread for each log entry. That will get expensive quickly.
Like James, I agree that you should use an established logging library. Logging is not as trivial as it seems, and there are already many solutions.
That said, if you want a nice .NET 4.5-based approach, it's pretty easy:
public abstract class BaseLogger
{
private readonly ActionBlock<LogEntry> block;
protected BaseLogger(int maxDegreeOfParallelism = 1)
{
block = new ActionBlock<LogEntry>(
entry =>
{
Log(entry);
},
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = maxDegreeOfParallelism,
});
}
public virtual void AddLogEntry(LogEntry entry)
{
block.Post(entry);
}
protected abstract void Log(LogEntry entry);
}
Regarding the loosing waiting messages on app crush because of unhandled exception, I've bound a handler to the event AppDomain.CurrentDomain.DomainUnload. Goes like this:
protected ManualResetEvent flushing = new ManualResetEvent(true);
protected AsyncLogger() // ctor of logger
{
AppDomain.CurrentDomain.DomainUnload += CurrentDomain_DomainUnload;
}
protected void CurrentDomain_DomainUnload(object sender, EventArgs e)
{
if (!IsEmpty)
{
flushing.WaitOne();
}
}
Maybe not too clean, but works.