Multi Threaded Programming with Java






Introduction

In this tutorial I will show how simple multi threaded programming can be with Java.

For this I will introduce the usage of the class Thread and the critical region synchronized.

As example for those techniques I will use a simple implementation of a multiplayer game lounge.

Structure of the program

In my multiplayer lounge there will be two threads: one to accept incoming requests (SocketServerThread) and one to answer requests and restart the SocketServerThread if there occur problems (LoungeServer).

Further there will be one shared data structure which will be accessed from both threads: the jobList_.

How to start threads

So now let us first take a look at the main program and how to create and start a thread:
public static void main(String[] args) 
{
  int port = 4224; 

  LoungeServer server = 
	  	new LoungeServer( port );
	  	  
  try
  {
    server.start();
    server.join();
  }
  catch( InterruptedException e )
  {
  }
}

So first we create a thread class and than start the thread by calling start(). Now the thread will execute it's run-method.

Then we wait for the thread to terminate by calling join.

The InterruptedException will occur if any other thread calls the method interrupt of our thread. In my program this will not happen, but we don't want to propagate this exception, so we just catch it everytime where it could occur.

The run-method of a thread

So now we will take s short look on the constructor of LoungeServer where the second thread (SocketServerThread) and the shared data structure (jobList_) are created:
public class LoungeServer 
  extends Thread
{
  public LoungeServer( int port )
  {
    running_ = true;
    jobList_ = new Vector();
    socketServerThread_ = new SocketServerThread( this, port );
  }

With this done we take a look at the run method.

While the thread is in the status running_ it checks first if the SocketServerThread is also still running and if not starts it. After that it processes the next job.
public void run()
{
  while( running_ )
  {
    if( !socketServerThread_.isAlive() )
    {
      socketServerThread_.start();
    }
    dispatchJob( popJob() );
  }
  socketServerThread_.done();
}

When a thread should no longer run we just set it's status running_ to false by calling the method done()
public void done()
{
  running_ = false;
}

Receiving jobs

Next we will again take a short look at the constructor of SocketServerThread:
public class SocketServerThread
  extends Thread
{
  public SocketServerThread( LoungeServer s, int port )
  {
    port_ = port;
    running_ = true;
    socket_ = null;
    server_ = s;
   }

The run method just opens a ServerSocket and accepts all incoming messages which will then be stored in the jobList_ of server_ via pushJob
public void run()
{
  try
  {
    socket_ = new ServerSocket( port_ );
			
    while( running_ )
    {
      java.net.Socket clientSock = socket_.accept();
      String data = SocketData.readLine( clientSock, false, 5000 );
      server_.pushJob( new JobEntry( clientSock, data ) );
    }
    socket_.close();
  }
  catch( java.io.IOException e )
  {
  }
}

JobEntry is just a class which stores the Socket and String:
public class JobEntry
{
  public JobEntry( Socket s, String d )
  {
    socket_ = s;
    data_ = d;
  }

Storing jobs and using synchronized for shared data structures

Now let's take a look at the method pushJob and how to garantuee that only one thread at a time writes to the jobList_.

When two threads write simultaneous to the same data structure it can come to inconsistencies.

To avoid such situations we can use the synchronized technique in Java to allow only one thread at a time access to a class.
public void pushJob( JobEntry job )
{
  synchronized( jobList_ ) 
  {
    jobList_.add( job );
    jobList_.notify();
  }
}

notify is called to wake up a thread which is waiting for a job to be inserted into an empty list.

Dispatching jobs

Finally let us take a look on the other thread and how it dispatches the jobs placed in jobList_.

First it takes the oldest job from the list:
public JobEntry popJob()
{
  JobEntry res;
  synchronized( jobList_ ) 
  {
    while( jobList_.isEmpty() )
    {
      try
      {
        jobList_.wait();
      }
      catch( InterruptedException e )
      {
      }
    }
    res = (JobEntry) jobList_.remove( 0 );			
   }
		
   return res;
}

Here synchronized garantuees again that only one thread at a time accesses the jobList_ and the call to wait() assertes that at least one job is stored in the list.

Finally this job will be passed to the method dispatchJob and processed there.

Summary

In this short tutorial I've shown how easy multi threaded programming can be with Java.

As multi threaded programming gets more and more important (just take a look at dual-core, quad-core CPUs) I think Java offers one of the easiest way for multi threaded programming.

But you should not forget that multi threaded programming itself is not as easy as just understanding the techniques of the programming language. You also need a lot to know about concurrent programming, workload distribution and avoiding of deadlocks, to just name some topics. A multi threaded approach where one thread is just idle gives you no performance improvements over the solution without those thread. Probably you will even loose a little bit performance in such a case.





Startseite

Impressum



Bei Problemen mit diesen Internetseiten schreiben sie bitte eine Email an mich!