Java

Thread Starvation in Java

Thursday, January 28th, 2010

I’ve been working with Threads in Java recently and have come across the issue of starvation. This is where a thread is unable to run because another thread is hogging the locks. To demonstrate this problem I have written a simple buffer. It has a list of objects that can be written and read. The reading thread must wait if the list is empty and the writing thread must wait if the list is full.

    1 class Buffer {

    2    volatile LinkedList data;

    3    int bufferMaxSize;

    4 

    5    public Buffer(int bufferMaxSize) {

    6       data = new LinkedList();

    7       this.bufferMaxSize = bufferMaxSize;

    8    }

    9 

   10    public synchronized T getData() throws InterruptedException {

   11       if (data.size() == 0) {

   12          try {

   13             wait();

   14          } catch (InterruptedException e) {

   15          }

   16       }

   17       notifyAll();

   18       return this.data.remove(0);

   19    }

   20 

   21    public synchronized void setData(T data)

   22       throws InterruptedException {

   23       if (this.data.size() == bufferMaxSize) {

   24          try {

   25             wait();

   26          } catch (InterruptedException e) {

   27          }

   28       }

   29       this.data.add(data);

   30       notifyAll();

   31    }

   32 }

I wrote a simple producer and consumer to test this. The problem is that until the buffer is full, the producer is starved of access to the buffer and must wait. In the example below where the max buffer size is set to 1000.

While that might be OK for a lot of situations. If you want to have fair access to the resources, then you have to manage it yourself. The notify() and notifyAll() all messages will just wake every/any waking thread. Once the lock is available then any Thread, including the one that just relinquished it, can take the lock. If that happens, then the thread must continue to wait until the lock is available.

Making your own locks rather than using the synchronized keyword will let you control which Thread is woken when a lock is relinquished but this does create an overhead that will have a performance hit. If you want alternate access to a buffer then it may be better to not have a list inside it that can buffer the data and instead just have 1 value that can’t be overwritten until it has been read.

This is only an example that shows the problem I was having but it can show itself in a number of different ways so it is something to look out for. Often using the debugger won’t show this since it is a problem of timing, putting in breakpoints slows everything down and so you can’t really see the problem.

Tags: , ,

Programming Comments Off

Starting external processes in Java

Wednesday, September 9th, 2009

This is mainly for my own reference in the future but thought that I would post it here as well as I couldn’t really find anything on this while looking it up.

Launching an external process in Java is done through the ProcessBuilder class. Runtime.exec can be used as well but this just calls ProcessBuilder itself.

The constructor for ProcessBuilder takes a String vararg of the executable and the arguments. There is also the method ProcessBuilder.directory(File directory) to set the directory the process is launched from. ProcessBuilder.start() starts the process and then returns a Process object for the process.

ProcessBuilder builder =

   new ProcessBuilder("exe", "arg 1", "arg 2", "arg 3");

builder.directory(new File("/path/to/working/dir"));

Process process = builder.start();

The part that I found the be awkward is the way that arguments are handled. You have to have 1 element per argument, as in the example above, having spaces doesn’t matter, the program will still treat it as one argument. Passing it as “\”arg 1\”" is unnecessary, the program will receive it as “arg 1″ with speech marks included. The example where I was having problems involved start ksh and getting it to run a program and pipe that into another. From command line it was:

ksh -c “exec arg | tee exec.log”

However, to run this from ProcessBuilder I needed

ProcessBuilder builder =

   new ProcessBuilder("ksh", "-c", "exec arg | tee exec.log");

Where the value of the -c parameter was passed as one argument. Some things I tried that didn’t work were:

ProcessBuilder builder =

   new ProcessBuilder("ksh", "-c", "\"exec arg | tee exec.log\"");

 

ProcessBuilder builder =

   new ProcessBuilder("ksh", "-c", "exec", "arg", "|", "tee", "exec.log");

 

ProcessBuilder builder =

   new ProcessBuilder("ksh", "-c exec arg | tee exec.log");

There were a few others as well. The problem is that with the first one of them, ksh would execute “exec arg | tee exec.log” including the speech marks so it wouldn’t find it, just as if you had typed that into a terminal. The second one, ksh would execute exec but then arg would be passed as an argument to ksh rather than exec and the same for all the others after it. The final one, ksh would receive the whole thing as single argument and so wouldn’t recognize it as it is expecting [-c] [command] as 2 arguments rather than one.

Tags: ,

Programming Comments Off