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 --- Mike Bresnahan <mike at fruitioninc.com> wrote: > From: "Bill Gladen" <nobody170 at yahoo.com> > To: <tclug-devel at mn-linux.org> > Sent: Monday, July 16, 2001 7:14 AM > Subject: Re: [TCLUG-DEVEL] Java Interfaces and multi-extends? > > > > I think I should preface this with a disclaimer to everyone else > > reading this. All points presented by both sides of the discussion > are > > correct. Most of the work of designing a system is in choosing one > of > > many ways to do something, and making tradeoffs between various > goals > > of programming. > > Both opinions may be correct, but mine is the most correct. ;) > > > Yes, the interface to the RDBMS is dynamically typed, but the data > in > > it generally is not. This is a case of dynamic typing being > > *unavoidable*. To implement an interface to a system that stores > > arbitrary data, you need your interface to handle arbitrary data > types. > > Therefore, they (correctly) made the tradeoff to dynamic typing. > If > > you do not *need* to handle arbitrary data, you shouldn't. This is > the > > same for the container classes; they need to handle arbitrary data, > so > > they are dynamically typed. > > My point is that by considering the data to be dynamically typed, you > can > write code that is more general. For example, you can write one > toString() > function instead of one for every data holder class. To illustrate > this > further, see the following code: > > // Multiple statically typed data holder classes design > > class DataHolder1 { > private String a; > private int b; > public String getA() { return a; } > public int getB() { return b; } > public String toString() { return "{a=" + a + ",b=" + b + "}"; } > } > > class DataHolder2 { > private String a; > private double b; > private java.util.Date c; > public String getA() { return a; } > public int getB() { return b; } > public java.util.Date getC() { return c; } > public String toString() { return "{a=" + a + ",b=" + b + ",c=" + > c + > "}"; } > } > > class DataHolder3 { > // ... > } > > class DataHolder4 { > // ... > } > > // ... on and on and on... until DataHolderBizillion > > // Single dynamically typed holder class design > > class Tuple { > private java.util.Hashtable map; > public Object get( String key) { > return map.get( key); > } > public void put( String key, Object value) { > map.put( key,value); > } > public String toString() { > StringBuffer buffer = new StringBuffer(); > buffer.append("{"); > java.util.Enumeration enum = map.keys(); > while( enum.hasMoreElements()) { > String key = (String)enum.nextElement(); > Object value = map.get( key); > buffer.append( key); > buffer.append("="); > buffer.append( value); > buffer.append(","); > } > buffer.append("}"); > return buffer.toString(); > } > > As a excercise for the reader, make changes to each implementation to > make > toString() use '[' intead of '{'. When you're done, tell me which > design > you spent the most time making the changes to. > > This is just a simple example. A more complex example is a function > that > inserts the data into a given table in a given database. > > > Data validation. > > > > Yes, you could make a Tuple class that validated it's data, but it > > would have to break the principle of abstraction to do so. You > would > > have to check what was going in (the key probably) to see if you > wanted > > to validate the field or not. This breaks abstraction because the > key > > is no longer a generic and arbitrary key object, but something to > be > > checked on input, and you would have to document in the interface > every > > 'special case' key, and what it's requirements are. If you have > more > > than one validated field, this will get really ugly very quickly. > > Allow me to change my mind. I don't think I would put validations in > a > tuple class. Tuple is simply a data holder, not a data processor. I > would > put the data validation in the data processing classes. > > > Design Patterns. > > > > I suppose I should say that they are over used in *some* places. > > > > Heh; this is probably my most unpopular opinion. With the > exception, > > perhapse of my opinion on EJBs. Design Patterns (ala gang-of-four > > book) are all the rage right now. They are useful solutions to > know, > > and solve some sticky problems if you happen to have those > problems. > > > > Every single one of them, however breaks the KISS principle. If > you > > read the book, it actually states this right in the beginning, and > > warns against using them if you don't need them. > > > > Notice that I didn't say don't use them, just be careful. If you > > overuse them you end up with a system that is too complex to use > and > > maintain. > > What is the KISS principle - Keep It Super Simple? > > I don't follow you here. Why do you think patterns produce overly > complex > solutions? The idea is that they are the best of breed of solutions, > no? > If there is a better way to do something then perhaps that way should > be a > pattern! > > What is your opinion of EJB? My opinion is that the entity bean > model is > misguided for the same reasons we have been discussing here. I think > it > breeds bizillions of boring data holder classes along with bizillions > of > lines of redundant code. I'm not strong with this opinion yet, > because I > have not actually done any EJB development. > > > You can use a producer-consumer pattern, but you could also use > > something simple like: > > > > // note that I'm leaving out the synchronization and error > handling, > > // they're almost, but not quite, trivial > > ... > > for( i = 0; i < NUMBER_OF_PROCESSING_THREADS; i++ ){ > > Thread t = new Thread( new Runnable(){ > > public void run(){ > > while( true ){ > > if( jobQueue.hasNext() ){ > > ((Job)jobQueue.next()).runJob(); > > }else{ > > sleep( SLEEP_TIME ); > > } > > } > > } > > } ); > > t.setDaemon( true ); // VERY IMPORTANT!! > > t.start(); > > } > > I'm confused. This IS the producer consumer pattern. Well ok, its > part of > it. You haven't shown the rest of the code, e.g. the implemenation > of > jobQueue.hasNext() and you haven't used a good performing > sychronization > === message truncated === __________________________________________________ Do You Yahoo!? Get personalized email addresses from Yahoo! Mail http://personal.mail.yahoo.com/