How to get the value to be calculated in another thread

There are many cases where stream A requires a value that must be calculated in stream B. (Most often, B == EDT.) Consider this example:

String host; SwingUtilities.invokeAndWait(new Runnable() { public void run() { host = JOptionPane.showInputDialog("Enter host name: "); } }); openConnection(host); 

Of course, this does not compile because the anonymous inner class is not allowed to write to host . What is the easiest, cleanest way to get this to work? I have included the methods that I know about below.

+3
source share
7 answers
<Not p> No:

Use Future<T> and possibly Callable<T> and ExecutorService . A Future is basically an exact programming expression of what you want: a promise of a future response and the ability to block until an answer is available . The future also automatically wraps and presents for you a whole, complex Farrago of potential nightmares and difficulties in the form of several clearly defined exceptions. This is a good thing because it forces you to deal with them when the roll-your-own solution probably never opens them except in some aberrant, hard-to-diagnose behavior.

 public void askForAnAnswer() throws TimeoutException, InterruptedException, ExecutionException { Future<String> theAnswerF = getMeAnAnswer(); String theAnswer = theAnswerF.get(); } public Future<String> getMeAnAnswer() { Future<String> promise = null; // spin off thread/executor, whatever. SwingUtilities.invokeAndWait(new Runnable() { public void run() { host = JOptionPane.showInputDialog("Enter host name: "); } }); // ... to wrap a Future around this. return promise; } 

In your particular case, you can probably build a SwingWorker that implements Future . Instead of a duplicate, please take a look at this SO question .

+2
source
  final SynchronousQueue<String> host = new SynchronousQueue<String>(); SwingUtilities.invokeAndWait(new Runnable() { public void run() { host.add(JOptionPane.showInputDialog("Enter host name: ")); } }); openConnection(host.poll(1, TimeUnit.SECONDS)); 
+1
source

Verbose: use inner class

 class HostGetter implements Runnable{ volatile String host; public void run() { host = JOptionPane.showInputDialog("Enter host name: "); } } HostGetter hg = new HostGetter(); SwingUtilities.invokeAndWait(hg); openConnection(hg.host); 
0
source

I recommend creating a class for processing, samples below:

 class SyncUserData implements Runnable { private String value ; public void run() { value = JOptionPane.showInputDialog("Enter host name: ") ; } public String getValue() { return value ; } } // Using an instance of the class launch the popup and get the data. String host; SyncUserData syncData = new SyncUserData() ; SwingUtilities.invokeAndWait(syncData); host = syncData.getValue() ; 

I will continue this approach by making an abstraction of the class and using generics so that any value types are returned.

 abstract class SyncUserDataGeneric<Type> implements Runnable { private Type value ; public void run() { value = process(); } public Type getValue() { return value ; } public abstract Type process() ; } String host; SyncUserDataGeneric<String> doHostnameGen ; doHostnameGen = new SyncUserDataGeneric<String>() { public String process() { return JOptionPane.showInputDialog("Enter host name: "); } }; host = doHostnameGen.getValue() ; 

EDIT: checks if from EventDispatchThread works.

 if (SwingUtilities.isEventDispatchThread()) { host = doHostnameGen.process() ; } else { SwingUtilities.invokeAndWait(doHostnameGen) ; host = doHostnameGen.getValue() ; } 
0
source

Please note: the author does not like this answer, he simply "on the nose" answers a specific question.

If you are looking only to minimize the above code to make it work, you are dealing with the problem of the inner class-only-refer-to-finals. Cut the named inner class instead of the anonymous one and create a String host field in this class. Pass this instance of invokeAndWait() . But this is still bad, in my humble opinion, and far below the Future<> approach that I quoted above.

 class FooWidget implements Runnable() { AtomicReference<String> host = new AtomicReference<String>(null); @Override public void run() { host.set(JOptionPane.showInputDialog("Enter host name: ")); } } ... FooWidget foo = new FooWidget(); SwingUtilities.invokeAndWait(foo); if (foo.host.get() == null) { throw new SomethingWentWrongException(); } openConnection(foo.host.get()); 
0
source

Elegant? Use atomic variable

 final AtomicReference<String> host = new AtomicReference<String>(); SwingUtilities.invokeAndWait(new Runnable() { public void run() { host.set(JOptionPane.showInputDialog("Enter host name: ")); } }); openConnection(host.get()); 
-one
source

Hack: use an array

 final String[] host = new String[1]; SwingUtilities.invokeAndWait(new Runnable() { public void run() { host[0] = JOptionPane.showInputDialog("Enter host name: "); } }); openConnection(host[0]); //maybe not guaranteed to be visible by the memory model? 
-one
source

Source: https://habr.com/ru/post/1397841/


All Articles