You are receiving this e-mail because you elected to receive e-mail from Sun Microsystems, Inc. To update your communications preferences, please see the link at the bottom of this message. We respect your privacy and post our privacy policy prominently on our Web site http://sun.com/privacy/
  Welcome to the Core Java Technologies Tech Tips.
Core Java Technologies
TECHNICAL TIPS
August 16, 2005
View this issue as simple text
In this Issue
 
Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SE).

This issue covers:

» Using InetAddress for Host Name Lookup and Host Reachability
» Locks

These tips were developed using the Java 2 Platform Standard Edition Development Kit 5.0 (JDK 5.0). You can download JDK 5.0 at http://java.sun.com/j2se/1.5.0/download.jsp.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc.

See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms.

For more Java technology content, visit these sites:

java.sun.com - The latest Java platform releases, tutorials, and newsletters.

java.net - A web forum where enthusiasts of Java technology can collaborate and build solutions together.

java.com - Hot games, cool apps -- Experience the power of Java technology.

USING INETADDRESS FOR HOST NAME LOOKUP AND HOST REACHABILITY
 

The InetAddress class has been around since the initial release of the Java platform. It provides for the identity of a host through an Internet Protocol (IP) address. In other words, if you type in a name like yahoo.com, you can find out its IP address with the help of the InetAddress class.

The InetAddress class design might seem a bit odd. There are no public constructors for the class, only static creators. Instances are immutable, meaning that once you have an instance of the class, you can't change it. However, that design was done for Java security purposes. A user can't change the results between lookups.

Here's an example that demonstrates the use of the InetAddress class. The following program, Lookup, identifies the name and IP address of the arguments you pass in from the command line:

   import java.net.*;

   public class Lookup {

     public static void main(String args[]) {
       for (String name: args) {
         try {
           InetAddress address = InetAddress.getByName(name);
           System.out.println("Name: " + address.getHostName());
           System.out.println("Addr: " + address.getHostAddress());
         } catch (UnknownHostException e) {
           System.err.println("Unable to lookup " + name);
         }
       }
     }
   }

The getByName() method in the program acts like the nslookup command in Microsoft Windows and Unix. It takes the name specified in the command line argument and then does a lookup in the designated name server for the system. Typically, it does the lookup using the Domain Name System (DNS). The lookup works either for a name, like yahoo.com, or an IP address, like 66.94.234.13. If you enter yahoo.com, you get 66.94.234.13. If you enter 66.94.234.13, you get the name of the host farm at Yahoo. In this case, the public name of the host is w2.rc.vip.scd.yahoo.com.

   > java Lookup sun.com yahoo.com 66.94.234.13

     Name: sun.com
     Addr: 209.249.116.195
     Name: yahoo.com
     Addr: 216.109.112.135
     Name: w2.rc.vip.scd.yahoo.com
     Addr: 66.94.234.13
	 

Some host names resolve to multiple IP addresses. Instead of using the getByName() method of InetAddress to look up a single name, you can use the getAllByName() method to get an array of InetAddress objects.

Also, the InetAddress class offers support for reverse name resolution. This means that you can look up the IP address for a particular host and then use that IP address to look up the host name. If the two don't match, this isn't necessarily wrong. However if you know that the two are supposed to match, a mismatch might indicate a spoofing attack.

The LookupAll program below uses the getAllByName() method to look up all addresses for a host. It then uses the getCanonicalHostName() method to look up the fully-qualified domain name for the host.

   import java.net.*;

   public class LookupAll {
     public static void main(String args[]) {
       for (String name: args) {
         try {
           InetAddress address[] = 
               InetAddress.getAllByName(name);
           for (InetAddress each: address) {
             System.out.println("Name: " + each.getHostName());
             System.out.println("Addr: " + 
                 each.getHostAddress());
             System.out.println("Canonical: " + 
                 each.getCanonicalHostName());
           }
           System.out.println("----");
         } catch (UnknownHostException e) {
           System.err.println("Unable to lookup " + name);
         }
       }
     }
   }

One such host with multiple addresses is google.com. The following example includes google.com and yahoo.com as arguments. The example better demonstrates how the reverse lookup of the IP address for yahoo.com resolves to a different host name.

   >> java LookupAll yahoo.com google.com

      Name: yahoo.com
      Addr: 216.109.112.135
      Canonical: w2.rc.vip.dcn.yahoo.com
      Name: yahoo.com
      Addr: 66.94.234.13
      Canonical: w2.rc.vip.scd.yahoo.com
      ----
      Name: google.com
      Addr: 216.239.39.99
      Canonical: 216.239.39.99
      Name: google.com
      Addr: 216.239.57.99
      Canonical: 216.239.57.99
      Name: google.com
      Addr: 216.239.37.99
      Canonical: 216.239.37.99
      ----

The getCanonicalHostName() method was added to the 1.4 version of the J2SE platform.

With J2SE 5.0, you can also use InetAddress to check for a host for reachability. In other words, you can determine if the host is "alive." This test is typically done from the command line with the "ping" command or with a simple TCP ECHO request. But why bother opening a command line prompt, possibly using the ProcessBuilder class explained in the July 27, 2005 Tech Tip From Runtime.exe to ProcessBuilder? Instead, all you need to use is the isReachable() method in InetAddress.

The isReachable() method comes in two forms:

  • public boolean isReachable(int timeout) throws IOException
  • public boolean isReachable(NetworkInterface netif, int ttl, int timeout) throws IOException

For most people, the first version of isReachable is sufficient. With this format, you simply provide a timeout for the check. The timeout represents the number of milliseconds to wait to see if the destination host is alive. The method returns "false" if the host is dead, the ping service is disabled, or the request is blocked at a firewall. If you locate a reachable host, the method returns "true". If a network error occurs, the method throws an IOException.

The second version of isReachable allows you to identify which NetworkInterface to use for the test. It also allows you to specify the maximum number of hops to try to reach a particular host. If you only have one network interface, but you want to specify the number of hops, pass in null for any interface. As is the case for the first version of isReachable, you also specify a timeout value. The possible return values for this version of isReachable are the same as for the one-argument version.

The following program, LookupReach, adds a reachable check to the earlier single name lookup:

   import java.io.*;
   import java.net.*;

   public class LookupReach {
     public static void main(String args[]) {
       for (String name: args) {
         try {
           InetAddress address = InetAddress.getByName(name);
           System.out.println("Name: " + address.getHostName());
           System.out.println("Addr: " + 
               address.getHostAddress());
           System.out.println("Reach: " + 
               address.isReachable(3000));
         } catch (UnknownHostException e) {
           System.err.println("Unable to lookup " + name);
         } catch (IOException e) {
           System.err.println("Unable to reach " + name);
         }
       }
     }
   }

Try running LookupReach with yahoo.com. sun.com, and google.com as arguments. You'll see that the program returns "false". Internet sites for most big web companies have disabled the service or blocked the requests. Also try running the program with an argument for a university site, like web.mit.edu. Sites for most universities allow the request.

   > java LookupReach yahoo.com sun.com google.com web.mit.edu
   
     Name: yahoo.com
     Addr: 216.109.112.135
     Reach: false
     Name: sun.com
     Addr: 209.249.116.195
     Reach: false
     Name: google.com
     Addr: 216.239.37.99
     Reach: false
     Name: web.mit.edu
     Addr: 18.7.22.69
     Reach: true

When you use the InetAddress class, keep in mind that you can specify commonly-used IPv4 names in the form of a.b.c.d. You can also specify the newer IPv6 names in the form x:x:x:x:x:x:x:x, where the 'x's are the hex values of the eight 16-bit pieces of the address. For more information about the IPv6 architecture, see RFC 2373.

If you aren't sure which version a name represents, you can check if the InetAddress is an instance of Inet4Address or Inet6Address. This is more commonly done for user-supplied addresses.

One last thing worth mentioning: name lookups and reverse lookups can be expensive operations. The system uses a cache mechanism for both performance and security reasons. Once you look up a host, you always know you'll get the same one, and the results can't change between lookups.



Back to Top

LOCKS
 

One of the popular features of the J2SE 5.0 libraries is the addition of concurrency utilities. Provided as part of JSR 166, the utilities provide advanced concurrency programming capabilities that take developers beyond the synchronized keyword and related synchronized blocks. One of the areas improved by the concurrency utilities is locking. Among the capabilities that it offers, the concurrency utilities support lock timeouts, multiple condition variables per lock, read-write locks, and the ability to interrupt a thread waiting for a lock. For more information about the additional lock support, see the documentation for the java.util.concurrent.locks package.

The foundation of the package is the Lock interface, which offers a series of methods for acquiring and releasing a lock. The typical usage sequence is: get a lock, access the protected resource, and release the lock. Here is the typical usage pattern:

     Lock l = ...;
     l.lock();
     try {
         // protected resource access
     } finally {
         l.unlock();
     }

When the Lock class is used in this way, it works similarly to a typical synchronized lock:

    synchronized(lockVariable) {
        // protected resource access
    }

Similar but not the same. If you don't get the unlock() call in a finally block, your application won't function properly. With the synchronized block, that isn't necessary.

Another method provided by the Lock interface that acquires a lock is lockInterruptibly(). After a thread requests a lock, it waits. The lockInterruptibly() method allows you to interrupt the waiting thread. The lock() method doesn't. If interrupt() is called on a thread that is waiting for the lock with lockInterruptibly(), the wait will be interrupted. The waiting thread then wakes up and an InterruptedException is thrown. In this case, no attempt is made to access the protected resource, and any other operations continue.

The typical usage pattern for the lockInterruptibly() method is:

    Lock l = new ReentrantLock();
    try {
        l.lockInterruptibly();
        try {
            // protected resource access
        } finally {
            l.unlock();
        }
    } catch (InterruptedException e) {
        System.err.println("Interrupted wait");
    } 

Here, the inner try-finally handles exceptions while the resources are held. The outer try-catch handles exceptions acquiring the resource. You should never call unlock if the lock acquisition fails.

A word of caution: calling lockInterruptibly() does not necessarily mean you can interrupt the wait. Not all Lock implementations support the operation.

Another method provided by the Lock interface, tryLock(), brings timeouts into play. The tryLock() method comes in two versions. The first version accepts no arguments. It tries to get the lock, and immediately fails if the lock isn't available:

    Lock lock = ...;
    if (lock.tryLock()) {
      try {
        // protected resource access
      } finally {
        lock.unlock();
      }
    } else {
        // alternative operation
    }

This is like going to the copy machine, seeing that someone is busy with a long copy job, and moving on to a slower but available machine for the task.

The second version of the tryLock method accepts two parameters to signify a timeout. The first argument is a long variable to specify the maximum wait time. The second argument is a TimeUnit for specifying the unit of time.

For instance, lock.tryLock(300, TimeUnit.MILLISECONDS) attempts to acquire a lock. If it can't get the lock after waiting for 300 milliseconds, it returns false, indicating the inability to get the lock. By comparison, lock.tryLock(30, TimeUnit.SECONDS) waits a maximum of 30 seconds. You need to explicitly specify both the value and the units.

The TimeUnit class allows you to specify units as seconds, milliseconds, microseconds, or nanoseconds.

1 second = 1 thousand milliseconds
1 second = 1 million microseconds
1 second = 1 billion nanoseconds

Although you've seen how to use the Lock interface, you haven't seen how to actually create a Lock. The prior examples all show:

   Lock lock = ...;

The java.util.concurrent.locks package includes three implementations of the Lock interface:

  • ReentrantLock
  • ReentrantReadWriteLock.ReadLock
  • ReentrantReadWriteLock.WriteLock

The first implementation, ReentrantLock, is the one typically used. The other two implementations are inner classes of the ReentrantReadWriteLock class. The ReentrantReadWriteLock class contains two locks: ReadLock and WriteLock.

For ReentrantLock, the typical usage pattern is:

     Lock l = new ReentrantLock();
     l.lock();
     try {
         // protected resource access
     } finally {
         l.unlock();
     }

Use a read-write lock when reads are long and frequent, and writes are infrequent. Your access to a protected object would then use separate locks acquired as shown here:

  ReadWriteLock rwl = new ReentrantReadWriteLock();
  Lock readLock = rwl.readLock();
  Lock writeLock = rwl.writeLock();

You then use the locks in the same manner as the ReentractLock, using the lock appropriate for the type of access you want to perform.

The only implementation of the ReadWriteLock interface is the ReentrantReadWriteLock class itself.

For more information on the Lock support, see the package description



Back to Top

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
If you would like a reply to your comment, please submit your email address:
Note: We may not respond to all submitted comments.
Comments? Send your feedback on the Tech Tips: http://developers.sun.com/contact/feedback.jsp?category=sdn

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:
  • Enterprise Java Technologies Tech Tips. Get tips on using enterprise Java technologies and APIs, such as those in the Java 2 Platform, Enterprise Edition (J2EE).
  • Wireless Developer Tech Tips. Get tips on using wireless Java technologies and APIs, such as those in the Java 2 Platform, Micro Edition (J2ME).
You can subscribe to these and other Java technology developer newsletters or manage your current newsletter subscriptions on the Sun Developer Network Subscriptions page

ARCHIVES: You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/developer/JDCTechTips/index.html

IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://www.sun.com/privacy/
http://developer.java.sun.com/berkeley_license.html

© 2005 Sun Microsystems, Inc. All Rights Reserved. For information on Sun's trademarks see: http://sun.com/suntrademarks
Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc. 10 Network Circle, MPK10-209 Menlo Park, CA 94025 US