Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 
Search the JavaFAQ.nu
1000 Java Tips ebook

1000 Java Tips - Click here for the high resolution copy!1000 Java Tips - Click here for the high resolution copy!

Java Screensaver, take it here

Free "1000 Java Tips" eBook is here! It is huge collection of big and small Java programming articles and tips. Please take your copy here.

Take your copy of free "Java Technology Screensaver"!.

Easy Learn Java: Programming Articles, Examples and Tips - Page 409


Previous 1060 Stories (530 Pages, 2 Per Page) Next

Arrgh, someone wants to kill me!

Go to all tips in

The Java Specialists' Newsletter [Issue 043] - Arrgh, someone wants to kill me!

Author: Dr. Heinz M. Kabutz

JDK version:

Category: Language

You can subscribe from our home page: http://www.javaspecialists.co.za (which also hosts all previous issues, available free of charge Smile

Welcome to the 43rd edition of The Java(tm) Specialists' Newsletter, sent to 2885 Java experts in over 75 countries. This time, I am writing from a rather cold Deutschland (for my likings), though the inhabitants tell me it is actually quite warm again, and I get funny looks when I walk around wearing a thick jacket and a wooly hat. Whereas on South African roads, I am the speed king with my Alfa Romeo, here I drive in the slow lane (at 140km/h), so that the trucks can overtake me. Traffic is quite interesting here in the good ol' Germany. Did you know that since February, you are not allowed to use your indicators at a traffic circle in Germany?

Weshalb verbringe ich nun ein paar Wochen im kalten Deutschland, wenn ich doch den sch?nen Sommer in Kapstadt geniessen k?nnte? Gute Frage. In S?dafrika gibt es viele hochleistende Entwickler, die erstens gute Qualit?t bringen und zweitens dazu auch noch preiswert sind. Mit der weltweiten Flaute ist es wichtig auf jeden Cent zu achten, ohne dabei Qualit?t zu verlieren. F?r die n?chsten paar Wochen m?chte ich also versuchen Projekte innerhalb von Europa zu finden, die Java Experten ben?tigen und bei denen ich gute s?dafrikanische Resourcen liefern kann. Ich bin bis Ende April in Deutschland, wenn Ihre Firma Projekte hat die Sie ausgeben m?chten, w?rde ich Ihnen gerne einen Besuch abstatten, also schicken Sie mir doch bitte eine mail. Ich habe zus?tzlich noch ein paar offene Tage, an denen ich Java Beratung geben kann.

Whilst I am in Germany, I would like to organise a Java_Specialist_Treff get-together for my European readers so we can get the opportunity to meet each other. I will discuss some of my newsletters, we'll have some drinks together, basically have a nice, nerdy time Wink)) The meeting will be held in Karlsruhe, Baden-W?rttemberg, close to the French border. I have not fixed a date and time yet, so if you would like to attend, please send me a quick email and tell me what dates until 28th of April would be most suitable for you.

Arrgh, someone wants to kill me!

Approximately a year ago, I wrote a newsletter about hooking into the shutdown call. In that newsletter, I rather snidely remarked that the shutdown process had some deficiencies, which rendered it useless for situations where you want to abort the shutdown process and go back to the program. Once you're in shutting down state, the program will die.

After I published that newsletter, a South African friend, James Pereira, sent me a code snippet that used OS signals directly for detecting when the program was being closed. You can use this mechanism to write your own shutdown hook mechanism (even for JDK 1.2), and put in whatever features you need.

The code that he sent me used some classes from the sun.* packages to achieve this. Warning: The classes in the sun.* package hierarchy can be changed at the whim of Sun's fancy. In addition, you will probably not find a sun.* hierarchy in any VMs except Sun's, though I have not looked yet. The package that James pointed me to was sun.misc, containing a flea-market (i.e. jumble-sale) of classes, some useful, others badly designed. You've been warned - so please don't whinge if this does not work exactly like this on your IBM / MS / whatever VM.

When you press Ctrl+C in the command window, an OS signal is generated called SIGINT. This is the same on Windows and Unix. When you kill a program by pressing the little cross, or using your task manager, a SIGTERM signal is sent to your program, and it will not be back! What we can do is link into the signal handler and handle that signal any way we want to. For example:


import sun.misc.Signal;
import sun.misc.SignalHandler;

/**
 * The idea for this code came from James Pereira, this code
 * looks quite different to the well-structured, logically
 * named class he sent me.
 * The idea is that we register a handler for a Ctrl+C
 * signal and then handle it.
 */
public class Aaarggh {
  public static void main(String[] args) throws Exception {
    Signal.handle(new Signal("INT"), new SignalHandler () {
      public void handle(Signal sig) {
        System.out.println(
          "Aaarggh, a user is trying to interrupt me!!");
        System.out.println(
          "(throw garlic at user, say `shoo, go away')");
      }
    });
    for(int i=0; i<100; i++) {
      Thread.sleep(1000);
      System.out.print('.');
    }
  }
}

When you run this program, it will print dots onto the console and if you try to stop it with Ctrl+C, it will give you the following output and merrily carry on printing dots. You can either stop it by waiting for the 100 seconds or to kill it via the task manager. (Kill sends a SIGTERM signal, which is stronger than SIGINT)

.........Aaarggh, a user is trying to interrupt me!!
(throw garlic at user, say `shoo, go away')
..

Inside the signal handler you can do anything you want to, including calling System.exit(0) or Runtime.getRuntime().halt(0) if you don't want shutdown hooks to be called.

What signals can you catch? The answer to that question depends on the operating system you are running on. I managed to dig out a list for Windows and Solaris Sun JDK 1.2.2:

  • Windows: ABRT, FPE, ILL, INT, SEGV, TERM
  • Solaris: ABRT, ALRM, BUS, CHLD, CONT, EMT, FPE, HUP, ILL, INT, IO, KILL, PIPE, POLL, PROF, PWR, QUIT, SEGV, STOP, SYS, TERM, TRAP, TSTP TTIN, TTOU, URG, USR1, USR2, VTALRM, WINCH, XCPU, XFSZ

    Please don't ask me what events generate each of those signals. It's a miracle that I found that list of signals, sun.misc.Signal is written in such a way that if you pass in an incorrect String it throws an IllegalArgumentException at you. However, it does not tell you what the possible signals are. The most significant signals from within Java are SIG and TERM.

    Here is some code that is called whenever our program is killed:

    import sun.misc.Signal;
    import sun.misc.SignalHandler;
    
    public class SophisticatedShutdownSequence {
      private static boolean running = true;
      public static void init() {
        Runtime.getRuntime().addShutdownHook(new Thread() {
          public void run() {
            System.out.println("reached point of no return ...");
          }
        });
    
        SignalHandler handler = new SignalHandler () {
          public void handle(Signal sig) {
            if (running) {
              running = false;
              System.out.println("Signal " + sig);
              System.out.println("Shutting down database...");
            } else {
              // only on the second attempt do we exit
              System.out.println(" database shutdown interrupted!");
              System.exit(0);
            }
          }
        };
        Signal.handle(new Signal("INT"), handler);
        Signal.handle(new Signal("TERM"), handler);
      }
    
      public static void main(String args[]) throws Exception {
        init();
        Object o = new Object();
        synchronized (o) {
          o.wait(10000);
        }
        System.exit(0);
      }
    }
    

    If you run this and press Ctrl+C twice, or try kill the program once via task manager or by pressing the cross, you get the following output:

    Signal SIGINT
    Shutting down database...
     database shutdown interrupted!
    We have now reached the point of no return ...
    

    This shutting down sequence is a good opportunity for the State Pattern (see Gang of Four book). Due to popular request, I will try and show one Java Design pattern every 4 newsletters, and I might just start with the State Pattern. In addition, I will soon start doing book reviews on books that you should definitely have in your bookshelf.

    Switching off OS signals at runtime

    In JDK 1.3.1, Sun sneaked in a JVM runtime parameter to stop all this nonsense of hooking into signals.

    public class NoShutdownHookAllowed {
      public static void main(String[] args) throws Exception {
        try {
          Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
              System.out.println("Shutdown hook going mad");
            }
          });
        } catch(IllegalArgumentException ex) {
          System.out.println("Caught " + ex);
        }
        Thread.sleep(10000);
      }
    }
    

    Try running this with JDK 1.3.1 and beyond, and use the following command: java -Xrs NoShutdownHookAllowed The -Xrs setting reduces use of OS signals by Java/VM.

    What happens is that an IllegalArgumentException is generated after the thread has been added as a shutdown hook. This means that if you try to interrupt the code after it has been started, the shutdown hook will not be called. However, if you let the program finish naturally, it will run the shutdown hook. As far as I know, the -Xrs option is there to make it easier to write services in Java.

    That's enough for now, please remember to send me an email if you would like to attend our Java_Specialist_Treff in Baden-W?rttemberg during April, and tell me what dates would suit you best.

    Also dann, bis n?chste Woche...

    Heinz


    Copyright 2000-2004 Maximum Solutions, South Africa

    Reprint Rights. Copyright subsists in all the material included in this email, but you may freely share the entire email with anyone you feel may be interested, and you may reprint excerpts both online and offline provided that you acknowledge the source as follows: This material from The Java(tm) Specialists' Newsletter by Maximum Solutions (South Africa). Please contact Maximum Solutions for more information.

    Java and Sun are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Maximum Solutions is independent of Sun Microsystems, Inc.

  • 8646 bytes more | comments? | Printer Friendly Page  Send to a Friend | Score: 3.5
    Posted by jalex on Saturday, October 01, 2005 (00:00:00) (2431 reads)

    I defined an equals method, but Hashtable ignores it. Why?

    Go to all tips in Java IAQ by Peter Norvig

    Q: I defined an equals method, but Hashtable ignores it. Why?

    Answer: equals methods are surprisngly hard to get right. Here are the places to look first for a problem:
    1. You defined the wrong equals method. For example, you wrote:

      public class C {
        public boolean equals(C that) { return id(this) == id(that); }
      }

      But in order for table.get(c) to work you need to make the equals method take an Object as the argument, not a C:

      public class C {
        public boolean equals(Object that) { 
          return (that instanceof C) && id(this) == id((C)that); 
        } 
      }

      Why? The code for Hashtable.get looks something like this:

      public class Hashtable {
        public Object get(Object key) {
          Object entry;
          ...
          if (entry.equals(key)) ...
        }
      }

      Now the method invoked by entry.equals(key) depends upon the actual run-time type of the object referenced by entry, and the declared, compile-time type of the variable key. So when you as a user call table.get(new C(...)), this looks in class C for the equals method with argument of type Object. If you happen to have defined an equals method with argument of type C, that's irrelevent. It ignores that method, and looks for a method with signature equals(Object), eventually finding Object.equals(Object). If you want to over-ride a method, you need to match argument types exactly. In some cases, you may want to have two methods, so that you don't pay the overhead of casting when you know you have an object of the right class:

      public class C {
        public boolean equals(Object that) {
          return (this == that) 
                  || ((that instanceof C) && this.equals((C)that)); 
        }
      
        public boolean equals(C that) { 
          return id(this) == id(that); // Or whatever is appropriate for class C
        } 
      }
      

    2. You didn't properly implement equals as an equality predicate: equals must be symmetric, transitive, and reflexive. Symmetric means a.equals(b) must have the same value as b.equals(a). (This is the one most people mess up.) Transitive means that if a.equals(b) and b.equals(c) then a.equals(c) must be true. Reflexive means that a.equals(a) must be true, and is the reason for the (this == that) test above (it's also often good practice to include this because of efficiency reasons: testing for == is faster than looking at all the slots of an object, and to partially break the recursion problem on objects that might have circular pointer chains).
    3. You forgot the hashCode method. Anytime you define a equals method, you should also define a hashCode method. You must make sure that two equal objects have the same hashCode, and if you want better hashtable performance, you should try to make most non-equal objects have different hashCodes. Some classes cache the hash code in a private slot of an object, so that it need be computed only once. If that is the case then you will probably save time in equals if you include a line that says if (this.hashSlot != that.hashSlot) return false.
    4. You didn't handle inheritance properly. First of all, consider if two objects of different class can be equal. Before you say "NO! Of course not!" consider a class Rectangle with width and height fields, and a Box class, which has the above two fields plus depth. Is a Box with depth == 0 equal to the equivalent Rectangle? You might want to say yes. If you are dealing with a non-final class, then it is possible that your class might be subclassed, and you will want to be a good citizen with respect to your subclass. In particular, you will want to allow an extender of your class C to use your C.equals method using super as follows:

      public class C2 extends C {
      
        int newField = 0;
      
        public boolean equals(Object that) {
          if (this == that) return true;
          else if (!(that instanceof C2)) return false;
          else return this.newField == ((C2)that).newField) && super.equals(that);
        }
      
      } 

      To allow this to work, you have to be careful about how you treat classes in your definition of C.equals. For example, check for that instanceof C rather than that.getClass() == C.class. See the previous IAQ question to learn why. Use this.getClass() == that.getClass() if you are sure that two objects must be of the same class to be considered equals.

    5. You didn't handle circular references properly. Consider:

      public class LinkedList {
      
        Object contents;
        LinkedList next = null;
      
        public boolean equals(Object that) {
          return (this == that) 
            || ((that instanceof LinkedList) && this.equals((LinkedList)that)); 
        }
      
        public boolean equals(LinkedList that) { // Buggy!
         return Util.equals(this.contents, that.contents) &&
                Util.equals(this.next, that.next); 
        }
      
      } 

      Here I have assumed there is a Util class with:

        public static boolean equals(Object x, Object y) {
          return (x == y) || (x != null && x.equals(y));
        } 

      I wish this method were in Object; without it you always have to throw in tests against null. Anyway, the LinkedList.equals method will never return if asked to compare two LinkedLists with circular references in them (a pointer from one element of the linked list back to another element). See the description of the Common Lisp function list-length for an explanation of how to handle this problem in linear time with only two words of extra storge. (I don't give the answer here in case you want to try to figure it out for yourself first.)

    This tip is reprinted on JavaFAQ.nu by by courtesy of Peter Norvig I am thankful for his important contributions to my site - 21 Infrequently Answered Java Questions. Alexandre Patchine


    5187 bytes more | comments? | Printer Friendly Page  Send to a Friend | Score: 5
    Posted by jalex on Friday, September 30, 2005 (00:00:00) (3617 reads)

    Previous 1060 Stories (530 Pages, 2 Per Page) Next

    530| 529| 528| 527| 526| 525| 524| 523| 522| 521| 520| 519| 518| 517| 516| 515| 514| 513| 512| 511| 510| 509| 508| 507| 506| 505| 504| 503| 502| 501| 500| 499| 498| 497| 496| 495| 494| 493| 492| 491| 490| 489| 488| 487| 486| 485| 484| 483| 482| 481| 480| 479| 478| 477| 476| 475| 474| 473| 472| 471| 470| 469| 468| 467| 466| 465| 464| 463| 462| 461| 460| 459| 458| 457| 456| 455| 454| 453| 452| 451| 450| 449| 448| 447| 446| 445| 444| 443| 442| 441| 440| 439| 438| 437| 436| 435| 434| 433| 432| 431| 430| 429| 428| 427| 426| 425| 424| 423| 422| 421| 420| 419| 418| 417| 416| 415| 414| 413| 412| 411| 410|
    409
    | 408| 407| 406| 405| 404| 403| 402| 401| 400| 399| 398| 397| 396| 395| 394| 393| 392| 391| 390| 389| 388| 387| 386| 385| 384| 383| 382| 381| 380| 379| 378| 377| 376| 375| 374| 373| 372| 371| 370| 369| 368| 367| 366| 365| 364| 363| 362| 361| 360| 359| 358| 357| 356| 355| 354| 353| 352| 351| 350| 349| 348| 347| 346| 345| 344| 343| 342| 341| 340| 339| 338| 337| 336| 335| 334| 333| 332| 331| 330| 329| 328| 327| 326| 325| 324| 323| 322| 321| 320| 319| 318| 317| 316| 315| 314| 313| 312| 311| 310| 309| 308| 307| 306| 305| 304| 303| 302| 301| 300| 299| 298| 297| 296| 295| 294| 293| 292| 291| 290| 289| 288| 287| 286| 285| 284| 283| 282| 281| 280| 279| 278| 277| 276| 275| 274| 273| 272| 271| 270| 269| 268| 267| 266| 265| 264| 263| 262| 261| 260| 259| 258| 257| 256| 255| 254| 253| 252| 251| 250| 249| 248| 247| 246| 245| 244| 243| 242| 241| 240| 239| 238| 237| 236| 235| 234| 233| 232| 231| 230| 229| 228| 227| 226| 225| 224| 223| 222| 221| 220| 219| 218| 217| 216| 215| 214| 213| 212| 211| 210| 209| 208| 207| 206| 205| 204| 203| 202| 201| 200| 199| 198| 197| 196| 195| 194| 193| 192| 191| 190| 189| 188| 187| 186| 185| 184| 183| 182| 181| 180| 179| 178| 177| 176| 175| 174| 173| 172| 171| 170| 169| 168| 167| 166| 165| 164| 163| 162| 161| 160| 159| 158| 157| 156| 155| 154| 153| 152| 151| 150| 149| 148| 147| 146| 145| 144| 143| 142| 141| 140| 139| 138| 137| 136| 135| 134| 133| 132| 131| 130| 129| 128| 127| 126| 125| 124| 123| 122| 121| 120| 119| 118| 117| 116| 115| 114| 113| 112| 111| 110| 109| 108| 107| 106| 105| 104| 103| 102| 101| 100| 99| 98| 97| 96| 95| 94| 93| 92| 91| 90| 89| 88| 87| 86| 85| 84| 83| 82| 81| 80| 79| 78| 77| 76| 75| 74| 73| 72| 71| 70| 69| 68| 67| 66| 65| 64| 63| 62| 61| 60| 59| 58| 57| 56| 55| 54| 53| 52| 51| 50| 49| 48| 47| 46| 45| 44| 43| 42| 41| 40| 39| 38| 37| 36| 35| 34| 33| 32| 31| 30| 29| 28| 27| 26| 25| 24| 23| 22| 21| 20| 19| 18| 17| 16| 15| 14| 13| 12| 11| 10| 9| 8| 7| 6| 5| 4| 3| 2| 1|


    Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

    RSS feed Java FAQ RSS feed Java FAQ News     

        RSS feed Java Forums RSS feed Java Forums

    All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

    Interactive software released under GNU GPL, Code Credits, Privacy Policy