Benchmark: timing 1000 iterations of Odud, PMGurus, btrott, visnu... Odud: 10 wallclock secs ( 9.61 usr + 0.01 sys = 9.62 CPU) PMGurus: 6 wallclock secs ( 5.41 usr + 0.01 sys = 5.42 CPU) btrott: 7 wallclock secs ( 7.17 usr + 0.04 sys = 7.21 CPU) visnu: 11 wallclock secs (11.31 usr + 0.00 sys = 11.31 CPU) #### #!/usr/bin/perl -w use strict; use Benchmark; use vars qw/@words @common/; @words = qw/Notice the use of an anonymous inner class Here an instance of an unnamed class derived from Thread is created and a run method that calls endApp is defined for the class All of this means that when the application is about to terminate the JVM starts the thread representing by the passed-in thread object When the thread starts the run method is called The run method calls endApp which closes the log file This flushes the output buffer To underscore the effect of the shutdown hook comment out the addShutdownHook lines in ShutdownDemo You'll see that the log file is empty when the program terminates You can register multiple shutdown hooks In this case each thread that represents a hook is started in an unspecified order and the various threads run simultaneously You cannot register or unregister a shutdown hook after the shutdown sequence has started Doing so results in an IllegalStateException Because shutdown hooks run as threads you must use thread-safe programming techniques Otherwise you risk having threads interfere with each other Also it's wise to design your application for simple and fast shutdown processing For example you might run into trouble if your application uses services during shutdown that are themselves in the processing of being shut down There are cases where shutdown processing does not happen even if you have registered shutdown hooks One example is corrupted native methods for example when you dereference a null pointer in C code This feature is somewhat similar to the atexit library function in /; @common = qw|a an and at the to|; timethese(1000, { Odud => q{ my (@only, %r); foreach $r (@words){ $r{lc $r} = 1; } my @uniqwords = sort keys %r; @seen{@common} = (); foreach $item (@uniqwords) { push(@only,$item) unless exists $seen{$item}; } my @newwords = @only; }, PMGurus => q{ my %seen; @seen{@common} = (1) x @common; my @newwords = sort grep !$seen{+lc}++, @words; }, btrott => q{ my(%seen, %r); @seen{@common} = (); for my $r (@words) { next if exists $seen{ lc $r }; $r{lc $r} = 1; } my @newwords = sort keys %r; }, visnu => q{ my @newwords = sort keys %{+{ map { !$common{$_ = lc $_} ? ($_, 1) : () } @words }}; }, });