In Java we have SwingUtilities.invokeAndWait and SwingUtilities.invokeLater to invoke code on the event dispatching thread, but not on any given thread. They take a Runnable as parameter.
So how would we implement such a feature in Java ? We'll need a thread that has nothing better to do but try to dequeue items from its queue and invoke them (the items would be the pieces of code that we need invoked on that thread). Something like this:
package threading;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class Invoker { private static Thread myThread; private static BlockingQueue<Task> queue; private Invoker() { } public static void BeginInvoke(Task task) { if (myThread == null) { queue = new LinkedBlockingQueue<Task>(); myThread = new MyThread(queue); myThread.start(); } if (Thread.currentThread() != myThread) { try { queue.put(task); } catch(InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } } else { task.perform(); } } }
And the actual thread (I simulate the .NET delegate by using Java anonymous classes):
package threading; import java.util.concurrent.BlockingQueue; public class MyThread extends Thread { private final BlockingQueue<Task> taskQueue; public MyThread(BlockingQueue<Task> queue) { taskQueue = queue; } public void run() { while(true) { try { Task currentTask = taskQueue.take(); currentTask.perform(); } catch (InterruptedException e) { e.printStackTrace(); // Restore the interrupted status Thread.currentThread().interrupt(); } } } }
We need an interface for our task - either an existing one (Swing uses Runnable), or a new one, like:
package threading;
public interface Task { void perform(); }
Finally, the test class with the main method:
package threading; public class Test { public static void main(String[] args) { System.out.println("main thread: " + Thread.currentThread().getId() + " " + Thread.currentThread().getName()); Invoker.BeginInvoke(new Task() { public void perform() { System.out.println("perform task on thread: " + Thread.currentThread().getId() + " " + Thread.currentThread().getName()); } }); Invoker.BeginInvoke(new Task() { public void perform() { System.out.println("perform task again on thread: " + Thread.currentThread().getId() + " " + Thread.currentThread().getName()); } }); } }
It should come as no surprise the output:
main thread: 1 main
perform task on thread: 7 Thread-0
perform task again on thread: 7 Thread-0
No comments:
Post a Comment