I'm having an app which enables a customer to place an order for a ride (as in Uber), initially considered in a "WAITING" phase. When a driver accepts the order, it is automatically set in an "ACCEPTED" phase.
When ACCEPTED, the user is going to be redirected to another scene, telling him that he needs to wait for his rider to pick him up.
I decided to create a thread that checks every 250ms if the status of his order was set to ACCEPTED, like that:
public class AcceptanceRunnable implements Runnable {
private boolean running;
public AcceptanceRunnable() {
running = true;
}
public void run() {
do {
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (OrderService.checkIfAccepted(OrderSession.getOrder())) {
// move to other scene
break;
}
} while(running);
}
public void setRunning(boolean running) {
this.running = running;
}
}
This AcceptanceRunnable class gets instantiated within the controller in the initialize() method:
#FXML
public void initialize() throws InterruptedException, IOException {
sourceAddress.setText("From: " + OrderSession.getOrder().getSourceAddress());
destinationAddress.setText("To: " + OrderSession.getOrder().getDestinationAddress());
price.setText("You'll need to pay RON " +
UserService.calculatePrice(UserSession.getUser()) + " for this ride.");
acceptanceRunnable = new AcceptanceRunnable();
Thread t = new Thread(acceptanceRunnable);
t.start();
}
Everything works fine. If I just print out some lines while waiting for the order's status to get changed, it seems to be okay. The problem is, I want my user to be redirected to another scene, if his order gets accepted.
This means, I need to insert something in place of the comment made in my AcceptanceRunnable.run() method.
I also tried changing the scene by having a method called ifAccepted() inside my controller, which actually triggers the method that changes the scene:
if (OrderService.checkIfAccepted(OrderSession.getOrder())) {
try {
Class<?> controller = Class.forName("com.example.yuber.controllers.CustomerWaitController");
Method ifAccepted = controller.getMethod("ifAccepted");
ifAccepted.invoke(controller.newInstance());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
break;
}
But I only get some NullPointerException and I'm pretty sure that what I do here isn't really correct.
Any opinions?
As Slaw suggested, using Platform#runLater(Runnable) fixed my problem.
What I actually did was add my run() method from the Runnable inside my controller, renaming it to handleTread():
public void handleThread() {
do {
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (OrderService.checkIfAccepted(OrderSession.getOrder())) {
Platform.runLater(() -> {
try {
SceneService.NewScene("/com/example/yuber/accepted-view.fxml", (Stage) rootPane.getScene().getWindow(), rootPane.getScene());
} catch (IOException e) {
e.printStackTrace();
}
});
break;
}
} while(running);
}
Not using Platform.runLater(...) would result in receiving a Not on FX Application Thread error.
Everything seems to be fine now.
Related
I'm using the ReadData class from https://github.com/iota-community/java-iota-workshop/blob/master/src/main/java/com/iota/ReadData.java to retrieve a message from the Iota Tangle (essentially a distributed Network) via a hash value (the bundlehash).
That's my method:
private String readMessageFromHash(String BundleHash) {
final String[] s = new String[]{""};
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
s[0] = ReadData.getTMessage(BundleHash);
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return s[0];
}
I need the return value in my next line of code but without multithreading my program crashes.
With mutlithreading it sometimes works, but most of time it doesn't work (returns an empty String).
I tried using:
thread.start();
try {
while(s[0].length < 1){}
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return s[0];
but it just loops infinitely.
I think the issue is my program not waiting long enough for a response from the network.
try
{
someTask();
someTask2();
someTask3();
someTask4();
someTask5();
}
catch (Exception e)
{
// log the error
}
if one of my task fails, I want a log of what happened, but I want to continue running the rest of the tasks. I know I can surround each task method with its own try/catch, but is there a cleaner way so I don't have so many try/catch blocks?
The best way for this is for each of your methods to execute with a try/catch inside.
void someMethod(){
try{
//code of method 1
}catch(Exception e){
e.printstackTrace()
}
}
and then call them all without try/catch.
someTask();
someTask2();
someTask3();
someTask4();
someTask5();
Now if one fails, the other will just continue.
Assuming your task return void and take no parameters you could create a functional interface :
#FunctionalInterface
interface Task {
void perform() throws Exception;
}
then create a helper method that will handle logging and will take Task as parameter :
private static void invoke(Task task) {
try {
task.perform();
} catch (Exception e) {
// log here
}
}
And then use it :
class MyClass {
public static void main(String[] args) {
invoke(MyClass::someTask);
invoke(MyClass::someTask1);
}
private static void someTask() throws Exception {
System.out.println("Task 1");
}
private static void someTask1() throws Exception {
throw new Exception("Exception");
}
}
To run the rest of tasks, you have to put EVERY task in a separate ‘try’ block. It is a clean way to do so. Otherwise, how will you know which task failed and how will you debug it?
Also, It is considered as a good practice to put every expected error separately in catch block, starting from more specific and finishing with more general. So that you can immediately understand what what problem has happened and save time on debugging
try {
someTask1;
}catch (ClassNotFoundException e) {
// log the error
}catch (Exception e) {
// log the error
}
try {
someTask2;
}catch (ArithmeticException e) {
// log the error
}catch (ArrayIndexOutOfBoundsException e) {
// log the error
}catch (Exception e) {
// log the error
}
Maybe using a recursive method:
public void myMethod (int state){
try
{
switch(state) {
case 1:
state+=1;
someTask();
myMethod(state);
break;
case 2:
state+=1;
someTask2();
myMethod(state);
break;
case 3:
state+=1;
someTask3();
myMethod(state);
break;
default:
state=-1;
}
}
catch (Exception e)
{
// If some task had an exception, this catch call the next task, because the state variable incremented.
myMethod(state);
}
public static void main (String[] Args){
myMethod(1);
}
}
I'm trying to build an ane who take an empty bitmap
bitmapData = new BitmapData(size.width,size.height,false, 0x00000000);
acquire it, edit the bytebuffer in a different thread then release it.
Here's the call function code in the java part
public FREObject call(FREContext freContext, FREObject[] args) {
try {
FREBitmapData bitmapData = (FREBitmapData)args[0];
bitmapData.acquire();
ByteBuffer bytebuffer =
myTaskProcessingQueue.put(new Task(freContext,bitmapData,bytebuffer)); //edit the bitmap data in a specific thread
} catch (InterruptedException e) {
Log.e(TAG, "exception", e);
} catch (FREInvalidObjectException e) {
Log.e(TAG, "exception", e);
} catch (FREWrongThreadException e) {
Log.e(TAG, "exception", e);
}
return null;
}
And when I'm done with the bytebuffer :
new Handler(Looper.getMainLooper()).post(new Runnable () {
#Override
public void run () {
try {
Toast.makeText(task.context.getActivity(),"Toast",Toast.LENGTH_SHORT).show();
task.bitmapData.release();
} catch (FREInvalidObjectException e) {
Log.e("InitExtractorFunction", "FREInvalidObjectException", e);
} catch (FREWrongThreadException e) {
Log.e(TAG, "exception", e);
}
}
});
The toast instruction works fine, but the bitmapData.release() one throws a FREWrongThreadException even though I am on the main thread, and I can't find any documentation about this exception on the adobe website.
Any idea?
Edit :
Here's more code for the thread class where i'm editing the data :
private class MyTaskWorker extends Thread {
#Override
public void run() {
while (true) {
try {
processMyTask(myTaskProcessingQueue.take());
} catch (InterruptedException e) {
Log.e(TAG,"InterruptedException", e);
}
}
}
private void processMyTask(Task task) {
// do work with bytebuffer
new Handler(Looper.getMainLooper()).post(new Runnable () {
#Override
public void run () {
try {
Log.d(TAG, "Thread: " + Thread.currentThread().getName());
Toast.makeText(task.context.getActivity(),"Toast",Toast.LENGTH_SHORT).show();
task.bitmapData.release();
Log.i(TAG,"bitmap released");
} catch (FREInvalidObjectException e) {
Log.e(TAG, "FREInvalidObjectException", e);
} catch (FREWrongThreadException e) {
Log.e(TAG,"FREWrongThreadException", e);
}
}
});
}
}
Edit 2 :
I also tried to do both the acquire and the relase in the same background thread and still no dice. The only way I managed to make it work is when I do both the acquire and the release inside the call function, but I don't want to block the main thread to wait for the bitmap modification...
Just like regular multithreading, whenever you acquire a lock, it must be released by the same thread who locked it.
The documentation for this exception has the following description:
FRE_WRONG_THREAD The method was called from a thread other than the one on which the runtime has an outstanding call to a native extension function.
Thus when call() is called from a background thread, the background thread is the one that locks bitmapData, which means the main thread does not own the lock to release it later.
You can always test this by logging the thread name in each location:
Log.d(..., "Thread: " + Thread.currentThread().getName());
The solution will be to ensure that the release() method is invoked from the same place (thread) as call() (wherever this may be)
I have a thread which i wanted to run always until the JVM is stopped. What is the best way to do that ?
public void run() {
String event = sc.nextLine();
try {
queue.put(event); // thread will block here
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Just adding an infinite loop should do the trick
public void run() {
while(true){
String event = sc.nextLine();
try {
queue.put(event); // thread will block here
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
while (true) { runBody(); }
Add exception handling if necessary.
I have a Producer-Consumer problem to implement in Java, where I want the producer thread to run for a specific amount of time e.g. 1 day, putting objects in a BlockingQueue -specifically tweets, streamed from Twitter Streaming API via Twitter4j- and the consumer thread to consume these objects from the queue and write them to file. I've used the PC logic from Read the 30Million user id's one by one from the big file, where producer is the FileTask and consumer is the CPUTask (check first answer; my approach uses the same iterations/try-catch blocks with it). Of course I adapted the implementations accordingly.
My main function is:
public static void main(String[] args) {
....
final int threadCount = 2;
// BlockingQueue with a capacity of 200
BlockingQueue<Tweet> tweets = new ArrayBlockingQueue<>(200);
// create thread pool with given size
ExecutorService service = Executors.newFixedThreadPool(threadCount);
Future<?> f = service.submit(new GathererTask(tweets));
try {
f.get(1,TimeUnit.MINUTES); // Give specific time to the GathererTask
} catch (InterruptedException | ExecutionException | TimeoutException e) {
f.cancel(true); // Stop the Gatherer
}
try {
service.submit(new FileTask(tweets)).get(); // Wait til FileTask completes
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
service.shutdownNow();
try {
service.awaitTermination(7, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Now, the problem is that, although it does stream the tweets and writes them to file, it never terminates and never gets to the f.cancel(true) part. What should I change for it to work properly? Also, could you explain in your answer what went wrong here with the thread logic, so I learn from my mistake? Thank you in advance.
These are the run() functions of my PC classes:
Producer:
#Override
public void run() {
StatusListener listener = new StatusListener(){
public void onStatus(Status status) {
try {
tweets.put(new Tweet(status.getText(),status.getCreatedAt(),status.getUser().getName(),status.getHashtagEntities()));
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentTread.interrupt(); // Also tried this command
}
}
public void onException(Exception ex) {
ex.printStackTrace();
}
};
twitterStream.addListener(listener);
... // More Twitter4j commands
}
Consumer:
public void run() {
Tweet tweet;
try(PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("out.csv", true)))) {
while(true) {
try {
// block if the queue is empty
tweet = tweets.take();
writeTweetToFile(tweet,out);
} catch (InterruptedException ex) {
break; // GathererTask has completed
}
}
// poll() returns null if the queue is empty
while((tweet = tweets.poll()) != null) {
writeTweetToFile(tweet,out);
}
} catch (IOException e) {
e.printStackTrace();
}
}
You should check if your Thread classes are handling the InterruptedException, if not, they will wait forever. This might help.