I'm in the midst of porting a C# program over to Java that makes heavy use of delegates and the delegate's BeginInvoke method to notify of an event asynchronously. Take a data communication thread for example. It might have to notify another worker thread of its state as well as the GUI.
It seems to me that the best way to notify of the various events for different classes is to have an IClassNameHereWatcher interface that defines all of the types of events that the class "publishing" the event would need to notify about and then each class that needs to listen would implement this interface and register itself as a listener. The thing I'm not quite sure about is how to make this asynchronous. Here's approximately what I'm referring to:
public interface IFrobWatcher {
void frobDidSomething();
void frobReceivedData(object data);
}
public class Frob implements Runnable {
List<IFrobWatcher> watchers = new ArrayList<IFrobWatcher>();
private void run() {
while (true) {
// Long running task
if (blah) notifyWeDidSomething();
notifyOfData(someDataObject);
}
}
public void addWatcher(IFrobWatcher watcher) {
watchers.Add(watcher);
}
private void notifyWeDidSomething() {
for (IFrobWatcher watcher : watchers) {
watcher.frobDidSomething(); // How do I make this asynchronous?
}
}
private void notifyOfData(object someDataObject) {
for (IFrobWatcher watcher : watchers) {
watcher.frobReceivedData(someDataObject); // How do I make this asynchronous?
}
}
}
public class FrobWatcher implements IFrobWatcher {
private Frob frobToWatch;
public FrobWatcher(Frob frob) {
frobToWatch = frob;
frobToWatch.addListener(this);
}
public void FrobDidSomething() {
System.out.println("Frob did something!");
}
public void FrobReceivedData(object received) {
System.out.println("Frob received: " + received.ToString());
}
public static void main(string[] args) {
Frob f = new Frob();
FrobWatcher fw = new FrobWatcher(f);
(new Thread(f)).start();
}
}
And this is a fairly simplified example, but hopefully it conveys what I'm looking for. If something isn't clear or doesn't make sense, please comment and I'll try to clarify or fix the example.
I would recommend an Executor from the java.util.concurrent package.
This is how asynchronous callbacks are handled in the Raptor framework:
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(
filesPoller, 0 /*initial delay*/,
checkInterval,
TimeUnit.MILLISECONDS
);
NB. this scheduling is recurring.
Related
I have the following interfaces:
public interface NumberOfCellsListener {
public void numberOfCellsChanged(int patientId, int numOfCells);
}
public interface NumberOfCells {
public void register(NumberOfCellsListener listener);
public int numOfCells(int patientId);
}
public interface ProbabilityOfCancer {
//this may be a time consuming calculation
public double probability(int patientId, int numOfCells, bool gender, double weight);
}
This is the structure of my cancer probability calculator. My task is to implement this such that it can be called asynchronously due to the time consuming nature of the calculations. I am new to Java, can anyone please guide me on how to implement these interfaces? I am not sure about the structure i.e. what goes where. I am guessing I should get the new number of cells from the method numberOfCellsChanged in NumberOfCellsListener's implementation. But since it is a void method, I am not sure what to do.
An Interface method that does not return something usually has the function of changing the internal state, or of using some other means of output (for example to print something to the console, send something over a network, or save it to a database or file.).
As for the specific interfaces:
A Listener as in NumberOfCellsListener is meant to be installed ('registered') with an object that calls a listener's method, in case a specific event occures. In your case, based on the interface name, I would assume, that your method is called, when the number of cells of some object changes. So the question for you should be, what that information (at that point) requires you to do, and do that in the method.
A class implementing NumberOfCells is supposed to make true of the above statement. It has a register method, that should put the listener in some sort of collection (maybe a List - e.g. an ArrayList?) and then, when a certain event occures, invoke all the list's listener's numberOfCellsChanged-methods.
So an example implementation could be:
public class NumberOfCellsPrinter implements NumberOfCellsListener {
public void numberOfCellsChanged(int patientId, int numOfCells) {
System.out.println("The number of cells for parentId:" + parentId + " has changed to " + numOfCells + ".");
}
}
...
public class PetriDish implements NumberOfCells {
private ArrayList<NumberOfCellsListener> listeners = new ArrayList<>();
private int numOfCells = 0;
public void register(NumberOfCellsListener listener) {
if (listener != null && !listeners.contains(listener)) {
listeners.add(listener);
}
}
public int numOfCells(int patientId) {
for (NumberOfCellsListener listener : listeners) {
listener.numberOfCellsChanged(parentId, numOfCells);
}
return numOfCells;
}
}
While this example is totally meaningless, and will always produce 0 as numOfCells, it should demonstrate the idea of listeners.
It is very important, that you familiarize yourself with the risks and traps concerning parallelism, since this is a key factor of your objective.
Try the following to learn about async callbacks in Java. You can find more tutorials and explanations here
// Java program to illustrate Asynchronous callback
interface OnGeekEventListener {
// this can be any type of method
void onGeekEvent();
}
class B {
private OnGeekEventListener mListener; // listener field
// setting the listener
public void registerOnGeekEventListener(OnGeekEventListener mListener)
{
this.mListener = mListener;
}
// My Asynchronous task
public void doGeekStuff()
{
// An Async task always executes in new thread
new Thread(new Runnable() {
public void run()
{
// perform any operation
System.out.println("Performing operation in Asynchronous Task");
// check if listener is registered.
if (mListener != null) {
// invoke the callback method of class A
mListener.onGeekEvent();
}
}
}).start();
}
// Driver Program
public static void main(String[] args)
{
B obj = new B();
OnGeekEventListener mListener = new A();
obj.registerOnGeekEventListener(mListener);
obj.doGeekStuff();
}
}
class A implements OnGeekEventListener {
#Override
public void onGeekEvent()
{
System.out.println("Performing callback after Asynchronous Task");
// perform some routine operation
}
// some class A methods
}
I am trying to implement an Annotation based Event System for my OpenGL Game Engine. I apply the #EventListener Annotation on the method which I want to be called like this:
#EventListener(type = Type.COLLISION)
public void OnCollision(CollisionEvent data)
{
System.out.println("HI");
}
The class in which this method sits implements an Empty Interface:
public class Sprite implements EventHandler
The EventDispatcher class:
public class EventDispatcher
{
private static List<EventHandler> registered = new ArrayList<EventHandler>();
public static void register(EventHandler EventHandler)
{
if (!registered.contains(EventHandler))
{
registered.add(EventHandler);
}
}
public static void unregister(EventHandler EventHandler)
{
if (registered.contains(EventHandler))
{
registered.remove(EventHandler);
}
}
public static List<EventHandler> getRegistered()
{
return registered;
}
public static void dispatch(final Event event)
{
new Thread()
{
#Override
public void run()
{
call(event);
}
}.start();
}
private static void call(final Event event)
{
for (EventHandler registered : getRegistered())
{
Method[] methods = registered.getClass().getMethods();
for (int i = 0; i < methods.length; i++)
{
System.out.println("Annotation Being Checked");
if (methods[i].isAnnotationPresent(EventListener.class))
{
System.out.println("Has Annotation");
Class<?>[] methodParams = methods[i].getParameterTypes();
if (methodParams.length < 1)
{
continue;
}
if (!event.getClass().getSimpleName().equals(methodParams[0].getSimpleName()))
{
continue;
}
try
{
methods[i].invoke(registered.getClass().newInstance(), event);
} catch (Exception exception)
{
System.err.println(exception);
}
} else System.out.println("No Annotation");
}
}
}
}
But when I run the program, It always prints out
Annotation Being Checked
No Annotation
multiple Times.
Can someone help? If more information is needed, please ask and I will edit the Question.
I setup a project based on your example and it's working fine. You will however see some "No Annotation" messages as your code evaluates all methods of the Sprite event handler. Even if you don't implement any additional methods other than OnCollision each class will inherit default methods from Object such as equals, hashCode or toString.
Test class:
public class SpriteTest {
public static void main(String[] args) {
EventDispatcher.register(new Sprite());
CollisionEvent collisionEvent = new CollisionEvent();
EventDispatcher.dispatch(collisionEvent);
}
}
Apart from that there are some obvious flaws in your code:
Don't use stateful static members (EventDispatcher.registered) unless you know what you're doing and are aware of the multithreading aspects that come with it
You store instances of EventHandler but only use the class information and create a new instance on the fly - why not register the class instead of an instance directly
You fork new Threads for each to be dispatched event. This is very bad practice as thread creation is a costly operation. Use a thread pool instead and submit runnables or callables
You check if the class' simple names match to see if a handler method is applicable. This will break when using inheritance and should be replaced by Class.isAssignableFrom
In general usage of annotations here is questionable. You're probably better off using dedicated interfaces for the different event types. Instead of a generic EventHandler there could be a CollisionEventHandler and so on...
Rough implementation idea
public interface CollisionEventHandler extends EventHandler {
void onCollision(CollisionEvent event);
}
public class Sprite implements CollisionEventHandler {
public void onCollision(CollisionEvent data) {
System.out.println("HI");
}
}
public class EventDispatcher {
...
static void call(final CollisionEvent event) {
getRegistered().stream()
.filter(handler -> handler instanceof CollisionEventHandler)
.map(handler -> (CollisionEventHandler) handler)
.forEach(handler -> handler.onCollision(event));
}
}
To handle different types of events you will need different call/dispatch methods. Maybe you can use the Visitor pattern (though I'm not a fan of it).
As we know, ThreadPoolExecutor uses some BlockingQueue as a queue of incoming tasks. What I want is to have ThreadPoolExecutor that has a second queue for the task results which are ready. I want to use this queue as a source for input/output services which send or store these results.
Why I want to create a separate queue? Because I want to decouple action of sending results from action of obtaining results. Also, I suppose any Exceptions and Delays that accompany input/output operations should not affect my ThreadPoolExecutor which is calculating the result.
I have created some naive implementation of this. I would like to get some criticism on this. May be, it can be implemented with out-of-the-box Java classes better? I use Java 7.
public class ThreadPoolWithResultQueue {
interface Callback<T> {
void complete(T t);
}
public abstract static class CallbackTask<T> implements Runnable {
private final Callback callback;
CallbackTask(Callback callback) {
this.callback = callback;
}
public abstract T execute();
final public void run() {
T t = execute();
callback.complete(t);
}
}
public static class CallBackTaskString extends CallbackTask<String> {
public CallBackTaskString(Callback callback) {
super(callback);
}
#Override
public String execute() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
return hashCode() + "-" + System.currentTimeMillis();
}
}
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
final BlockingQueue<String> resultQueue = new LinkedBlockingQueue<String>();
Callback<String> addToQueueCallback = new Callback<String>() {
#Override
public void complete(String s) {
System.out.println("Adding Result To Queue " + s);
resultQueue.add(s); //adding to outgoing queue. some other executor (or same one?) will process it
}
};
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 5, 1000l, TimeUnit.DAYS, workQueue);
for (int i = 0; i <= 5; i++) {
executor.submit(new CallBackTaskString(addToQueueCallback));
};
System.out.println("All submitted.");
executor.shutdown();
executor.awaitTermination(10l, TimeUnit.SECONDS);
System.out.println("Result queue size " + resultQueue.size());
}
}
For the sake of makinf a library component, you would have to wrap things up...
You could extend The thread pool executor which has a number of methods to intercept the submitted tasks, so you would queue thing out to a queue passed in the constructor.
That's basically ExecutorCompletionService, but you would allow the user to plug a queue instead of appearing as one.
Otherwise, this is typical proxying of the task. Fair job.
I am trying to make an application in Java.
To make Swing work correctly, I did this:
public static void main(String[] array){
String outerInput;
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
// I want this string input.
String input = JOptionPane.showInputDialog(
null,"Stop ?", JOptionPane.QUESTION_MESSAGE);
});
// How can I get this input value in String outerInput?
}
How would I get this input string in my main body?
You can use AtomicReference<String> for passing values between threads in a thread-safe manner.
As noted by Hemal, you'll need some synchronization between two threads to make sure it was already executed. For example, you can use CountDownLatch or use SwingUtilities.invokeAndWait (make sure you don't call it from Swing thread!)
Update: here is the complete example using AtomicReference and CountDownLatch
public class Main {
public static void main(String[] args) throws InterruptedException {
final AtomicReference<String> result = new AtomicReference<String>();
final CountDownLatch latch = new CountDownLatch(1);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
String input = JOptionPane.showInputDialog(null, "Stop?", "Stop?", JOptionPane.QUESTION_MESSAGE);
result.set(input);
// Signal main thread that we're done and result is set.
// Note that this doesn't block. We never call blocking methods
// from Swing Thread!
latch.countDown();
}
});
// Here we need to wait until result is set. For demonstration purposes,
// we use latch in this code. Using SwingUtilities.invokeAndWait() would
// be slightly better in this case.
latch.await();
System.out.println(result.get());
}
}
Also read this answer about general design of GUI (and Swing) applications.
How would I get this input string in my main body?
You wouldn't. The idea that your "main" would invoke a Swing dialog box and then do something with the results is contrary to the entire idea of a graphical user interface.
In a GUI, you design your program to deal with a series of user-initiated events. Those events may be completely asynchronous, such as the keystrokes, selection, and menu choices of your typical word processor. Or they may be scripted, such as the question-answer format of a "wizard."
Assuming that you want to do something like the latter, you would implement it using the following sequence:
The user initiates some action, perhaps selecting a menu choice. This is turned into an invocation of an ActionListener, which decides that it needs more input from the user.
The ActionListener, which is executed on the event dispatch thread, is permitted to do anything that it wants to the UI, such as displaying a dialog. That dialog may be modal or non-modal; in one case the output is available to the original listener, in the other you need to write a new listener to take subsequent action.
Once you have enough information, you may choose to invoke a background operation. You would typically have a thread-pool to service these requests. You would not attempt to perform the request on the "main" thread; in fact, for all intents the main thread is no longer running.
When your operation completes running, it would push data back to the event dispatch thread using SwingUtilities.invokeLater(). While you could use invokeAndWait() to send results to Swing in the middle of your background operation, that's rarely a good idea. Instead, create a sequence of operations, preferably one that is easily canceled by the user.
The "standard" way to initiate operations on a background thread is via SwingWorker. There are alternatives; for example, you could use a BlockingQueue to send operations to a single long-running background thread, and use invokeLater() to return the results.
Regardless, there's one rule that you do not want to break: never, ever, perform a blocking operation on the event dispatch thread. If you do that, then your application is broken.
Right now you have two threads going: the main thread and the EDT (event dispatch thread). I assume you know that SwingUtilities.invokeLater(runnable) is running a task on the EDT.
To share data between threads, you just need some variable that is in the scope of both threads. The easiest way to accomplish that is to declare a volatile data member or AtomicReference in the class containing the main method.
In order to ensure that you read the value after it is returned by the JOptionPane, the simplest thing you can do here is to change the invokeLater call to an invokeAndWait call. This will cause your main thread to stop executing until what you have put onto the EDT has completed.
Ex:
public class MyClass {
private static volatile String mySharedData;
public static void main(String[] args) throws InterruptedException {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
mySharedData = JOptionPane.showInputDialog(null, "Stop ?", JOptionPane.QUESTION_MESSAGE);
}
});
// main thread is blocked, waiting for the runnable to complete.
System.out.println(mySharedData);
}
}
If your main thread is executing some task that shouldn't be stopped while the option pane is present, then in the main thread you can periodically check (i.e., in the outer part of the loop that is running your task) whether or not mySharedData has been set. If your task doesn't loop and is instead doing some I/O or waiting, you can make use of Thread.interrupt and check mySharedData in the InterruptedExecption handlers.
I suggest using the observer/observable pattern for this, perhaps with a PropertyChangeListener. Then your Swing app will be able to notify any and all listeners if the critical variable(s) state changes.
For example:
import java.awt.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.event.*;
public class ListenToSwing {
public static final String STATE = "state";
private static final int STATE_MAX = 10;
private static final int STATE_MIN = -10;
private JPanel mainPanel = new JPanel();
private int state = 0;
private JSlider slider = new JSlider(STATE_MIN, STATE_MAX, 0);
public ListenToSwing() {
mainPanel.add(slider);
slider.setPaintLabels(true);
slider.setPaintTicks(true);
slider.setMajorTickSpacing(5);
slider.setMinorTickSpacing(1);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
setState(slider.getValue());
}
});
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
mainPanel.addPropertyChangeListener(listener);
}
public Component getMainPanel() {
return mainPanel;
}
public void setState(int state) {
if (state > STATE_MAX || state < STATE_MIN) {
throw new IllegalArgumentException("state: " + state);
}
int oldState = this.state;
this.state = state;
mainPanel.firePropertyChange(STATE, oldState, this.state);
}
public int getState() {
return state;
}
public static void main(String[] args) {
final ListenToSwing listenToSwing = new ListenToSwing();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("ListenToSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(listenToSwing.getMainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
listenToSwing.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(ListenToSwing.STATE)) {
System.out.println("New state: " + listenToSwing.getState());
}
}
});
}
}
You can use an AtomicReference and invokeAndWait.
public static void main(String[] array){
AtomicReference<String> outerInput = new AtomicReference<String>();
SwingUtilities.invokeAndWait(new Runnable(){
#Override
public void run() {
String input = JOptionPane.showInputDialog(
null,"Stop ?", JOptionPane.QUESTION_MESSAGE);
outerInput.set(input);
});
outerInput.get(); //Here input is returned.
}
You can trivially expose it to the outer class by declaring a String[] in which the runnable sets the value. But note that you will need some synchronization mechanism to know whether it has been assigned by the Runnable.
The following code will do what you want. I have done something similar except I was launching a JFileChooser instead of an input dialog. I found it more convenient than hard coding a bunch of paths into my application or accepting a command line argument, at least for testing purposes. I would like to add that one could modify the prompt() method to return the FutureTask instance for added flexibility.
public class Question {
public static void main(String[] args) {
Question question = new Question();
String message = "Stop?";
System.out.println(message);
// blocks until input dialog returns
String answer = question.ask(message);
System.out.println(answer);
}
public Question() {
}
public String ask(String message) {
try {
return new Prompt(message).prompt();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
}
private class Prompt implements Callable<String> {
private final String message;
public Prompt(String message) {
this.message = message;
}
/**
* This will be called from the Event Dispatch Thread a.k.a. the Swing
* Thread.
*/
#Override
public String call() throws Exception {
return JOptionPane.showInputDialog(message);
}
public String prompt() throws InterruptedException, ExecutionException {
FutureTask<String> task = new FutureTask<>(this);
SwingUtilities.invokeLater(task);
return task.get();
}
}
}
I'm trying to implement a work queue in Java that limits the amount of work that can be taken at a time. In particular, it is trying to protect access to an external resource. My current approach is to use a Semaphore and a BlockingQueue so that I have something like this:
interface LimitingQueue<V> {
void put(Callable<V> work);
Callable<V> tryPoll();
}
It should behave like this:
#Test
public void workLimit() throws Exception {
final int workQueue = 2;
final LimitingQueue<Void> queue = new LimitingQueue<Void>(workQueue);
queue.put(new Work()); // Work is a Callable<Void> that just returns null.
queue.put(new Work());
// Verify that if we take out one piece of work, we don't get additional work.
Callable<Void> work = queue.tryPoll();
assertNotNull(work, "Queue should return work if none outstanding");
assertNull(queue.tryPoll(), "Queue should not return work if some outstanding");
// But we do after we complete the work.
work.call();
assertNotNull(queue.tryPoll(), "Queue should return work after outstanding work completed");
}
The implementation of tryPoll() uses Semaphore#tryAcquire and, if successful, creates an anonymous Callable that wraps the Semaphore#release call in a try/finally block around the call to work.call().
This works, but is somewhat unsatisfying in that if the user of this class puts work that is of some specific class that implements Callable, the user does not get access to that class back when looking at the result of tryPoll. Notably, tryPoll() returns a Callable<Void>, not a Work.
Is there a way to achieve what the work limitation effect while giving the caller back a usable reference to the work object that was submitted? (It's fine to strengthen the type signature of LimitingQueue to be more like LimitingQueue<R, T extends Callable<R>>.) I can't think of a way to ensure that the semaphore is released after calling the work item without doing this kind of wrapping.
EDIT2 I have replaced what was here with a suggestion on how to implement what you're looking for. Let me know if you want some of the old info back and I can restore it.
public class MyQueue<T> {
private Semaphore semaphore;
public void put(Work<T> w) {
w.setQueue(this);
}
public Work<T> tryPoll() {
return null;
}
public abstract static class Work<T> implements Callable<T> {
private MyQueue<T> queue;
private void setQueue(MyQueue<T> queue) {
if(queue != null) {
throw new IllegalStateException("Cannot add a Work object to multiple Queues!");
}
this.queue = queue;
}
#Override
public final T call() throws Exception {
try {
return callImpl();
} finally {
queue.semaphore.release();
}
}
protected abstract T callImpl() throws Exception;
}
}
Then use it like thus:
public class Test {
public static void main(String[] args) {
MyQueue<Integer> queue = new MyQueue<Integer>();
MyQueue.Work<Integer> work = new MyQueue.Work<Integer>() {
#Override
protected Integer callImpl() {
return 5;
}
};
queue.put(work);
MyQueue.Work<Integer> sameWork = queue.tryPoll();
}
}
Sounds to me like you should just use the builtin ExecutorService. Use Executors#newCachedThreadPool to get a pool, then submit Callable jobs which return back a Future.