Note to self: check out the SCons build tool at some point.
Monthly Archives: June 2003
A colleague coined this term the other day. Having no thoughts of my own at the moment due to work pressure, I thought I’d steal his:
Refuctoring. The opposite of refactoring. The process by which well fuctored code is achieved.
ASM gains ground
CGLib now uses ASM instead of BCEL.
CGLib really is pretty cool. One of my colleagues, Chris, had a go at writing an enhancing classloader using CGLib, but ran into difficulties with final classes and classloader recursion. It ought to be possible, and that seems to me to be the most logical place to inject the enhanced bytecode. The rest of the application would then be completely unaware of the enhancement and could just instantiate classes in the usual way.
java.net ate my brain!
Just found this article on java.net. The ideas seem strangely similar to those expressed in this entry from over a month ago. Hah! Exposed!
Okay, so the Sun article is better written, but they have had a month to do it 🙂
I’m not too bothered. Chances are I osmosed the idea from someone else in the first place anyway.
Thanks for reminding me
From the BileBlog:
The major flaw with dynamic mocks is that the return values are for all intents and purposes static. So for example, you can specify something like myMock.expectAndReturn(“getBlah”, “blah”); but cannot express something where the return value is not static. Why might you want to do that, you might wonder. Well, lets say you want to create a mock object for ServletContext, you’d want to be able to specify a Map that methods like getInitParameter and get/setAttribute work off of. Alas, this is impossible without much arm twisting and ugly hackery. You basically have to implement your own CallFactory which has all the extra magic in it. Maybe I’m missing something, but a less braindead solution to me would be to have the possibility of return values implementing some kind of interface, and in that special case, use a callback to determine what the actual return should be.
I have done exactly this, for the the purposes of erecting a fake servlet engine around some code that needed a more dynamic interaction with its environment than a straight mock object could provide. I’ve even been given permission to open source it, I just haven’t gotten around to it yet. I’ll see what I can do about getting it out there.
Striving for banality
Knowing as I do how many hits this site gets, I sometimes wonder if the pressure to be perceived as erudite and interesting results in excessive self-censorship at a semi-concious level.
I also wonder if my random writings will ever be as interesting as this. Sheer artistry. I’m humbled.
Concurrent coding for fun
Every now and then I like to get stuck into some hairy coding, just for fun. Concurrency and multithreaded objects are always good for a challenge. While waiting for a build yesterday I had a go at writing a Work Queue implementation, which is kind of like a service-orientated approach to thread pooling.
A work queue is simply an object that allows Runnables to be scheduled for execution and contains a number of threads internally that run in a loop, popping tasks off the queue and running them. Synchronisation is fun, as you have to properly manage multiple threads adding and removing tasks from the queue, as well as preventing both busy waiting (where threads spin in a tight loop, taking all your cpu but doing nothing) and excessive blocking (and of course deadlock). Proper use of wait() and notify() is essential.
Some thoughts that occurred: Threads live in methods. All method-level variables are per-thread. So while there might be many threads running the same method, from their perspective they are in glorious isolation. The places where threads go to meet other threads are an object’s fields, and wait() and notify() calls. This is where the fun lies. I tend to imagine calls to wait() as turnstiles, where threads queue up, waiting to be allowed through. When a thread calls notify() on an object other threads are waiting on, one of them is allowed to go through the turnstile and continue executing. Calling notifyAll() is like starting a melee, where all the waiting threads make a dive for the door. Only one can get through at a time, but they’re all going to try. The other important point is that although a waiting thread may have been notified (it’s pushing at the turnstile), it can’t get through until the thread that called notify() leaves the synchronized block. This is why calls to notify() are usually found at the end of synchronized blocks, or right before a call to wait(). One other thing I forgot to mention. When a thread hits a wait() call, it gives up the lock its holding on that object (remember that wait can only be called in a synchronized block), thus allowing other threads to run in that block (or other block synchronized on the same object). Clear as mud?
Some things to remember when writing multi-threaded classes:-
If you call wait(), you must call at least one notify() on the same object.
If you have to wait(long) to avoid deadlock, you probably forgot to notify().
Figuring out which object to synchronise on is important.
Nested synchronized blocks are really easy to deadlock. Avoid if possible.
Don’t synchronise your methods unless its to prevent concurrent modification to your fields. Methods can only be synchronised on their own object. Synchronised blocks can use any variable or field, which can get really hairy, but is much more flexible.
When thinking about threads, time is a variable. Threads (at the same priority) can run at the same speed, overtake one another, one could run from start to finish before the other gets moving, and anything in between. The only way to coordinate the activities of multiple threads is by careful use of synchronized, wait() and notify().
Oh, and forget that ‘synchronisation is slow’ myth. I once wrote a partially synchronized Map of Maps implementation where the main map was a regular hashmap and the submaps were synchronized. The theory was that in a multithreaded system that would allow greater concurrency. Turns out the cost of hashing twice was more expensive than using a simple synchronized map and letting the threads compete for it. Go figure.