[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[news.eclipse.platform.swt] Use case for Display.syncExec(Runnable runner) versus asyncExec

I am trying to figure out what is appropriate usage of the syncExec method on Display. If syncExec is what I understand it to be, then it basically will not return until after the runnable method has executed.

Take for example the following code (see snippet below for a fully functional example. Run with swt.jar on classpath)

	private void executeAsynchronously(Runnable runnable) {
		captureMethodEnteredTime();
		display.asyncExec(runnable);
		captureMethodExitedTime();
	}
	
	private void executeSynchronously(Runnable runnable) {
		captureMethodEnteredTime();
		display.syncExec(runnable);
		captureMethodExitedTime();
	}

private void captureMethodExitedTime() {
endTime = System.currentTimeMillis();
returnedAt.setText("Returned At : " + endTime + "(" + (endTime - startTime) + ") ms");
}


	private void captureMethodEnteredTime() {
		startTime = System.currentTimeMillis();
		enteredAt.setText("Entered At : " + startTime);
	}


Say that the runnable takes 10 seconds to execute, then in the case of the executeSynchronously method, the captureMethodExitedTime() should print out not earlier than 10 seconds after the syncExec was called. In the case of the asyncExec the captureMethodExitedTime() should print out almost immediately.


In which situations should we wait and in which should we do an async process? In either case, it seems like if the runnable is an inner class, it can update the UI with appropriate messages as needed.

I have included my sample code below. Interesting to see how the UI locks up when a long running runnable is processed versus if you spawn another thread to do the work in the runnable that keeps the UI responsive.

Thanks in advance,
Nik


//complete code below. Need swt.jar on classpath to execute package com.nikb.swt;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

/**
 * Shows the difference between synch and asych execution.
 *
 * @author Nbhattacharya
 *
 */
public class AsyncVersusSyncWindow {

	private Text text;
	private Display display;
	private Text finalOutput;
	private Button createSimpleRunnableButton;
	private Button createThreadedRunnable;
	private Text returnedAt;
	private Text enteredAt;
	private Button goButton;
	private Button syncExecButton;
	private Button asyncExecButton;
	private Label methodEnteredAt;
	private Label methodReturnedAt;
	public long startTime;
	private long endTime;
	protected boolean cancel;
	private static int count = 0;
	
	public AsyncVersusSyncWindow(){
		initialize();
	}

	private void initialize() {
		display = new Display();
		
		Shell asyncVersusSynchShell = new Shell(display);
		asyncVersusSynchShell.setText("Async Versus Synch Tester");
		final GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 2;
		asyncVersusSynchShell.setLayout(gridLayout);
		asyncVersusSynchShell.setBounds(200, 200, 595, 386);
		new Label(asyncVersusSynchShell, SWT.NONE);

final Group optionsGroup = new Group(asyncVersusSynchShell, SWT.NONE);
optionsGroup.setText("Options");
optionsGroup.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
final GridLayout gridLayout_2 = new GridLayout();
optionsGroup.setLayout(gridLayout_2);


		
		syncExecButton = new Button(optionsGroup, SWT.RADIO);
		
		syncExecButton.setText("Sync Exec");
		syncExecButton.setSelection(true);

		
		asyncExecButton = new Button(optionsGroup, SWT.RADIO);
		asyncExecButton.setText("Async Exec");

		final Group runnableTypeGroup = new Group(optionsGroup, SWT.NONE);
		runnableTypeGroup.setText("Runnable Type");
		runnableTypeGroup.setLayoutData(new GridData());
		runnableTypeGroup.setLayout(new GridLayout());
		
		createSimpleRunnableButton = new Button(runnableTypeGroup, SWT.RADIO);
		createSimpleRunnableButton.setText("Create simple runnable");


createThreadedRunnable = new Button(runnableTypeGroup, SWT.RADIO);
createThreadedRunnable.setLayoutData(new GridData());
createThreadedRunnable.setText("Create runnable that spawns another thread");
createThreadedRunnable.setSelection(true);

goButton = new Button(asyncVersusSynchShell, SWT.NONE);
goButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
doRunProcess();
}
});
goButton.setLayoutData(new GridData());
goButton.setText("Go!");


		final Button cancelButton = new Button(asyncVersusSynchShell, SWT.NONE);
		cancelButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				cancel = true;
			}
		});
		cancelButton.setText("Cancel");


methodEnteredAt = new Label(asyncVersusSynchShell, SWT.NONE); methodEnteredAt.setText("Method Entered At:");

		enteredAt = new Text(asyncVersusSynchShell, SWT.BORDER);
		enteredAt.setEnabled(false);
		enteredAt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

		
		methodReturnedAt = new Label(asyncVersusSynchShell, SWT.NONE);
		methodReturnedAt.setText("Method Returned At:");

		returnedAt = new Text(asyncVersusSynchShell, SWT.BORDER);
		returnedAt.setEnabled(false);
		returnedAt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

final Label label = new Label(asyncVersusSynchShell, SWT.SEPARATOR | SWT.HORIZONTAL);
label.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
new Label(asyncVersusSynchShell, SWT.NONE);


finalOutput = new Text(asyncVersusSynchShell, SWT.BORDER);
finalOutput.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));


final Group additionalGroup = new Group(asyncVersusSynchShell, SWT.NONE);
additionalGroup.setText("Additional");
final GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1);
gridData.widthHint = 575;
additionalGroup.setLayoutData(gridData);
final GridLayout gridLayout_1 = new GridLayout();
gridLayout_1.numColumns = 2;
additionalGroup.setLayout(gridLayout_1);


final Button testResponsivenessButton = new Button(additionalGroup, SWT.NONE);
testResponsivenessButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent e) {
text.setText(text.getText().concat(" Yes!"));
}
});
testResponsivenessButton.setText("Test Responsiveness");


		text = new Text(additionalGroup, SWT.BORDER);
		text.setLayoutData(new GridData());

		final Button clearFieldsButton = new Button(additionalGroup, SWT.NONE);
		clearFieldsButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				clearFields();
			}
		});
		clearFieldsButton.setText("Clear Fields");
		new Label(additionalGroup, SWT.NONE);
		asyncVersusSynchShell.open();
		
		
		while(!asyncVersusSynchShell.isDisposed()){
			if(!display.readAndDispatch()){
				display.sleep();
			}
		}
		
		display.dispose();
	}
	
	protected void doRunProcess() {
		clearFields();
		
		if(syncExecButton.getSelection()){
			executeSynchronously(getRunnableProcess("SYNC"));
		} else {
			executeAsynchronously(getRunnableProcess("ASYNC"));
		}
	}

	private Runnable getRunnableProcess(String type) {
		if(createSimpleRunnableButton.getSelection()){
			System.out.println("simple");
			return new LongSimpleRunnable(type);
		} else {
			System.out.println("threaded");
			return new LongRunnableWithInternalThread(type);
		}
	}

	private void clearFields() {
		cancel = false;
		text.setText("");
		enteredAt.setText("");
		returnedAt.setText("");
		finalOutput.setText("");
	}

	private void executeAsynchronously(Runnable runnable) {
		captureMethodEnteredTime();
		display.asyncExec(runnable);
		captureMethodExitedTime();
	}
	
	private void executeSynchronously(Runnable runnable) {
		captureMethodEnteredTime();
		display.syncExec(runnable);
		captureMethodExitedTime();
	}

private void captureMethodExitedTime() {
endTime = System.currentTimeMillis();
returnedAt.setText("Returned At : " + endTime + "(" + (endTime - startTime) + ") ms");
}


	private void captureMethodEnteredTime() {
		startTime = System.currentTimeMillis();
		enteredAt.setText("Entered At : " + startTime);
	}

public static void main(String[] args) {
AsyncVersusSyncWindow window = new AsyncVersusSyncWindow();
}

/**
* Spawns a thread in the run method and calls display.asyncExec to update the ui.
* The UI is not locked up.
*
* @author Nbhattacharya
*
*/
class LongRunnableWithInternalThread implements Runnable {

private String name;
private boolean wasCancelled;

public LongRunnableWithInternalThread(String name) {
this.name = name + " SPAWN NEW THREAD " + count++;
}

public void run() {
Thread oneThread = new Thread(){

public void run() {
final long start = System.currentTimeMillis();

display.asyncExec(new Runnable(){


public void run() {
finalOutput.setText("Running (" + name + ")..." + start); //this should throw an exception
}

});

for (int i = 0; i < 5; i++) {
if(!cancel){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
wasCancelled = true;
break;
}
}
final long end = System.currentTimeMillis();
display.asyncExec(new Runnable() {
public void run() {
finalOutput.setText(name + " " + (wasCancelled ? "cancelled" : "done") + " at" + end + "(" + (end - start) + ") ms");
}
});
}
};
oneThread.start();
}
}

/**
* A long runnning process in the run method. The UI locks up when the run is executed.
*
* @author Nbhattacharya
*
*/
class LongSimpleRunnable implements Runnable {


		private String name;

		public LongSimpleRunnable(String name) {
			this.name = name + " SIMPLE RUNNABLE " + count++;
		}

		public void run() {

long start = System.currentTimeMillis();
finalOutput.setText("Running (" + name + ")..." + start); //this should throw an exception


			for (int i = 0; i < 5; i++) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			long end = System.currentTimeMillis();

finalOutput.setText(name + " done at" + end + "(" + (end - start)+ ") ms");

		}
	}

	
	
}