We may end up having to agree to disagree.  Heh

Let me start with a disclaimer.  I have been guilty more than once of
creating overly complex solutions as a result of my passionate pursuit of
elegant, generic, and beautiful code.  I think it is the
mathematician/physitist in me.  I'm always seeking to make my code more and
more general and semmetric much like mathematicians and physiticts are
always seeking to find the underlying thereom or the grand unified theory.
So I understand first hand your concerns about unnecessary code complexity.
However, I do not feel I am guilty in the current context.

I create a new class called Tuple so that I can change the implementation
later without effecting client code - basic data abstraction.  I also find
that the name more clearly describes the class's role.  Additionally, I may
want to add more features.  For example, I may want the tuple to maintain
order of the elements.  java.sql.ResultSet does this.  You can retrieve a
column via its name or its index.  Hashtable does not allow this.

I feel the producer-consumer pattern is not nearly as complex as you're
making it out to be.  Here's some sample code off the top of my head based
on that found in Patterns in Java.

public class Producer implements Runnable {
    private Queue queue;
    public void run() {
        Thingy thingy = getThingy();
        queue.push( thingy);
    }
}

public class Consumer implements Runnable {
    private Queue queue;
    public run() {
        Thingy thingy = queue.pull();
    }
}

public class Queue {
    private java.util.LinkedList list = new java.util.LinkedList();
    public synchronized void push( Thingy thingy) {
        list.add( thingy);
        notify();
    }
    public synchronized Thingy pull() {
        if( list.size() == 0) {
            try {
                wait();
            }
            catch( InterrruptedException ex) {
            }
        }
        return (Thingy)list.removeFirst();
    }
}

I'd also like to make the point that there is more to software quality than
source code simplicity.  In fact, the most important software quality
criteria have nothing to do with source code, rather they have to do with
user satisfaction.  User's really don't care how simple, beautiful, or
maintainable your code is.  They only care how well it performs the work
they ask of it.  By not using the producer-consumer combined with a thread
pool you seem to favor code simplicity over user satisfaction.

I also believe that code simplicity is not always the road to
maintainability.  For instance, hard coding the number of worker threads
into the application may be simple, but it is a maintainence headache.
People supporting the software in the future will have to make code changes,
do testing, and do a rollout simply to do some simple performance tuning.
Hard coding anything like that is a big no-no in my book.

I've had to rewrite more than once code that used polling instead of proper
wait/notify semantics, because of the performance problem it was causing.  I
think 20 instructions per poll is an overly conservative estimate.  Can Java
get anything done in 20 cyles?  Additionally, if you plan to run this
application on a server shared by other applications you simply aren't being
a good neighbor by wasting precious cpu cycles.  Even with today's 1Ghz
processors, cpu cycles are not a renewable resource.  Perhaps you should
reconsider your refusal to sign the Kioto Protocol, Mr Bush.

Mike
----- Original Message -----
From: "Bill Gladen" <nobody170 at yahoo.com>
To: <tclug-devel at mn-linux.org>
Sent: Tuesday, July 17, 2001 6:23 AM
Subject: Re: [TCLUG-DEVEL] Java Interfaces and multi-extends?


> Okay, today's preface will be that I'm grumpy.
> On that note, I shall withdraw yesterday's preface and state that He's
> flat out wrong. :-)
>
> First, a toString() is one of the most trivial things you can put in a
> class, and generally not considered very important unless you need to
> debug your stuff. Try writing a clone() (a deep clone, no cheating) or
> implement the serializable interface (again with deep serialization) on
> the Tuple class.
>
> As for data validation, and not putting any in, why do you even have a
> Tuple class?  If there's no validation, and it's just a placeholder for
> data, then just use a HashMap.  If you need other functionality, write
> a utility class (it can even be completely static) that has a method to
> return a string from a HashMap.
>
> KISS = Keep It Simple, Stupid.
>
> As for the synchronization and implementation of jobQueue.hasNext(),
> here is the revised code.  Note the lack of reinvented wheels.
>
> ...
> LinkedList jobQueue = new LinkedList();
> for( i = 0; i < NUMBER_OF_PROCESSING_THREADS; i++ ){
>   Thread t = new Thread( new Runnable(){
>     public void run(){
>       Job job;
>       while( true ){
>         job = null;
>         synchronized( jobQueue ){
>           if( ! jobQueue.isEmpty() ){
>             job = (Job)jobQueue.removeFirst();
>           }
>         }
>         if( null != job ){
>           try{
>             job.runJob();
>           }catch( Throwable t ){
>             // handle this.
>           }
>         }else{
>           try{
>             sleep( SLEEP_TIME );
>           }catch( InterruptedException ie ){
>           }
>         }
>       }
>     }
>   } );
>   t.setDaemon( true );  // VERY IMPORTANT!!
>   t.start();
> }
>
> That's all off the cuff, so if there are syntax errors, don't nit-pick.
>
> As for the sleep vs. wait/notify, yes this will use cycles, but it will
> probably be about 20 instructions per idle cycle (it would be about 3,
> but synchronization is expensive), which translates into less than .1
> millisecond on today's processors.  If you are sleeping for 1 second,
> .01% is not enough to worry about.
>
> This way, the synchronization, processing, and run logic is in one
> place.
>
> If you implemented the classic producer/consumer pattern, you'd
> probably have 3 extra classes, and if you were using a pooled resource
> pattern for the Threads, that would be another 2 or 3 classes, and if
> you were using the Factory pattern to create the threads (so you could
> change the subclass of Thread or Runnable you used without changing any
> code) that would be ANOTHER 2 classes AND a properties file...
>
> If you think I'm just going off the deep end here, I've seen this kind
> of code.  Using it is a serious nightmare.
>
> Bill
>
>
>
>