Wednesday, October 2, 2013

Background process - Thread and Runnable

When you have a program that requires two or more processes run concurrently, you need to separate the processes in to different threads. Threading can ensure that while a process is running, other processes are not locked. For example, a web download program might need long time to complete a download task. If you don't put the download task in a thread, the user interface will be locked while the download process is still running. As the interface is locked, you cannot display any message to the user (for example, please wait...message). In addition, the user cannot do anything (e.g. add new address to the download list) with the interface and feel unresponsive. To avoid this problem you need to put the download task in background process or in a separated thread.
In Java, you can use the Thread class to create a thread object to run a process. The Thread class has a method called run that you have to override. The background process will be placed in the run method.

class BackgroundDownload extends Thread{
public void run(){
    //do the background or separated process here
  }
}

To run the thread, you need to create its object and call its start method.
Thread bp=new BackgroundDownload();
bp.start();

Below is a simple web downloader program. You can copy and paste the url of the file you want to download in the address text box and add it to the download list. The download task starts when you click the Download button. The user interface is not locked while the download process is running. You still can interact with the user interface as you can do before the download process begins. You see the message "Please wait..." before the download process immediately starts. And when the download process stops, you see the message "Download complete!". Your downloaded files will be stored in the current folder of your working project.


import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

class UI extends JFrame implements ActionListener{
DefaultListModel<String> listModel;
JList<String> listUrls;
JTextField textUrl;
JLabel lblwait;

UI(String title){
Container cont=getContentPane();
cont.setLayout(new BorderLayout());
setTitle(title);
setPreferredSize(new Dimension(600,300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel lbl=new JLabel("Address:");
textUrl=new JTextField(30);
JButton btadd=new JButton("Add");
btadd.addActionListener(this);
JButton btremove=new JButton("Remove");
btremove.addActionListener(this);
JPanel panelnorth=new JPanel();
panelnorth.add(lbl);
panelnorth.add(textUrl);
panelnorth.add(btadd);
panelnorth.add(btremove);
listModel=new DefaultListModel<String>();
listUrls=new JList<String>(listModel);
listUrls.setVisibleRowCount(10);
listUrls.setFixedCellWidth(200);
JScrollPane pane=new JScrollPane(listUrls);
JButton btok=new JButton("Download");
lblwait=new JLabel();
JPanel panelsouth=new JPanel();
panelsouth.add(btok);
panelsouth.add(lblwait);
btok.addActionListener(this);
cont.add(panelnorth, BorderLayout.NORTH);
cont.add(pane, BorderLayout.CENTER);
cont.add(panelsouth, BorderLayout.SOUTH);
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent e){
if(e.getActionCommand().equals("Add")){
if(!textUrl.getText().equals("")){
listModel.addElement(textUrl.getText());
textUrl.setText("");
}
else
JOptionPane.showMessageDialog(null, "Please enter the file or directory path", "Add path",JOptionPane.INFORMATION_MESSAGE);


}
else if(e.getActionCommand().equals("Remove")){
if(listModel.getSize()>0){
int selIndex=listUrls.getSelectedIndex();
if(selIndex>=0)
listModel.removeElementAt(selIndex);
else
JOptionPane.showMessageDialog(null, "No selected item", "Delete error",JOptionPane.ERROR_MESSAGE);
}
else
JOptionPane.showMessageDialog(null, "No item in the list", "Delete error",JOptionPane.ERROR_MESSAGE);
}
else if(e.getActionCommand().equals("Download")){
if(listModel.getSize()>0){
//create background process Thread object and start downloading the files
Thread bp=new BackgroundDownload();
bp.start();
}
else
JOptionPane.showMessageDialog(null, "No url is added to the download list", "Error",JOptionPane.ERROR_MESSAGE);
}
}

class BackgroundDownload extends Thread{
public void run(){
lblwait.setText("Please wait...");
for(int i=0;i<listModel.size();i++){
download(listModel.get(i));
}

lblwait.setText("Download complete!");
}
}

public void download(String address){
String storeDir=System.getProperty("user.dir");

try {
URL url=new URL(address);
HttpURLConnection con=(HttpURLConnection)url.openConnection();
InputStream is=con.getInputStream();
String filename=address.substring(address.lastIndexOf("/")+1);
String savepath=storeDir+File.separator+filename;
FileOutputStream fos=new FileOutputStream(savepath);
int bytedata=0;
while((bytedata=is.read())!=-1){
fos.write(bytedata);
}
fos.flush();
fos.close();
is.close();

} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}


public class BackgroundProcess {
public static void main(String[] args){
new UI("Thread-Background Process");
}


}

background process with Thread and Runnable- web downloader example



Another style to place the background process in a separated thread is to implement the Runnable interface. You also need to override the run method. To run the thread, first create an instance or object of the class and pass it as the argument of the Thread constructor when you create the Thread object to start the process.

class BackProcess implements Runnable{
public void run(){
   //do the background process here
  }
}
//start the process
BackProcess bp=new BackProcess();
Thread starter=new Thread(bp);
starter.start();

1 comment: