Strange Concurrency Issue in Java Swing -
i have jframe application's window (appframe in following code) contains lot of logic , takes 1 second or load. in meantime want show user nice loading frame (initframe). however, when run code, initframe appear text in jlabel on doesn't appear - doesn't appear @ in brief moment till app frame loaded.
if comment out appframe, , launch initframe, text loaded instantly, no waiting time @ all. why so? might concurrency issue?
public static void main(string[] args) { swingutilities.invokelater(new runnable() { //as per best practice concurrency in swing - see http://docs.oracle.com/javase/tutorial/uiswing/concurrency/ @override public void run() { final jframe initframe = new initframe(); initframe.setvisible(true); final appframe appframe = new appframe(); appframe.setvisible(true); initframe.setvisible(false); initframe.dispose(); } }); }
here's example of might going wrong in appframe
.
you can run test threading:
java splashtest true
or without
java splashtest
when threading enabled, see splashframe
, appframe
updating every 250ms, more or less.
when threading not enabled, see splashframe
no components showing, app 'hangs' 4 seconds, see appframe
.
the example contrived, might give ideas.
note splashframe
has no 'direct' connection appframe
. communication through appframeworklistener
interface.
i've put 'work' in appframe
. if there lot of processing done should extracted out of ui code, run in separate thread
, , appframe
notified of progress task, in same way splashframe
is.
import javax.swing.*; class splashtest { static boolean usethread = false; public static void main(string[] args) { // pass true @ command line turn on threading. // no args, or value other true turn off threading. if (args.length > 0) { usethread = new boolean(args[0]); } swingutilities.invokelater(new runnable() { @override public void run() { splashframe splashframe = new splashframe(); splashframe.setvisible(true); new appframe(splashframe).setvisible(true); }}); } private static class baseframe extends jframe { public baseframe() { setdefaultcloseoperation(jframe.dispose_on_close); setsize(200, 200); settitle(getclass().getsimplename()); } } private static class splashframe extends baseframe implements appframeworklistener { jlabel status; public splashframe() { setlocation(0, 0); status = new jlabel("splash frame"); getcontentpane().add(status); } public void appframeworkstart() { status.settext("work started"); } public void appframeworkprogress(long timeelapsed) { status.settext("work has taken " + timeelapsed + "ms far"); } public void appframeworkdone() { // http://stackoverflow.com/questions/1234912/how-to-programmatically-close-a-jframe setvisible(false); dispose(); } } private static class appframe extends baseframe { jlabel status; appframeworklistener listener; public appframe(appframeworklistener listener) { setlocation(200, 200); status = new jlabel("app frame"); getcontentpane().add(status); this.listener = listener; // none of 'heavy lifting' should in constructor. if (usethread) { new thread(new runnable() { @override public void run() { dolotsofwork(4); } }).start(); } else { dolotsofwork(4); onworkdone(); } } private void dolotsofwork(int worklengthseconds) { // we're starting. ensure onworkstart called on edt, // method may called different thread. invokeonworkstartonedt(); long start = system.currenttimemillis(); // hammer cpu "worklengthseconds" number of seconds. // , contrived progress reporting. long worklengthms = worklengthseconds * 1000; while (system.currenttimemillis() - start < worklengthms) { long innerstart = system.currenttimemillis(); // consume 250ms cpu before issuing progress update. while (system.currenttimemillis() - innerstart < 250); invokeonworkprogressonedt(system.currenttimemillis() - start); } // we're done now. ensure onworkdone called on edt, // method may called different thread. invokeonworkdoneonedt(); } private void invokeonworkstartonedt() { swingutilities.invokelater(new runnable() { @override public void run() { onworkstart(); } }); } private void invokeonworkprogressonedt(final long timeelapsed) { swingutilities.invokelater(new runnable() { @override public void run() { onworkprogress(timeelapsed); } }); } private void invokeonworkdoneonedt() { swingutilities.invokelater(new runnable() { @override public void run() { onworkdone(); } }); } private void onworkstart() { status.settext("work started"); if (null != listener) { // tell who's interested in work status. listener.appframeworkstart(); } } private void onworkprogress(long timeelapsed) { status.settext("work has taken " + timeelapsed + "ms far"); if (null != listener) { // tell who's interested in work status. listener.appframeworkprogress(timeelapsed); } } private void onworkdone() { status.settext("work done"); if (null != listener) { // tell who's interested in work status. listener.appframeworkdone(); } } } interface appframeworklistener { public void appframeworkdone(); public void appframeworkstart(); public void appframeworkprogress(long timeelapsed); } }
Comments
Post a Comment