home *** CD-ROM | disk | FTP | other *** search
/ Java Interactive Reference Guide / Java Interactive Reference Guide.iso / autorun / java_d.dir / 00057_introduction.txt < prev    next >
Encoding:
Text File  |  1980-01-11  |  24.0 KB  |  309 lines

  1. Interpreted, Dynamic, Secure, and Threaded
  2.  
  3.  
  4. ----------------------------------------------------------------
  5.  
  6.  
  7. 4.1 - Dynamic Loading and Binding
  8.  
  9.  
  10.  
  11. 4.2 - Security in the Java Environment
  12.  
  13.  
  14.  
  15. 4.3 - Multithreading
  16.  
  17.  
  18.  
  19. 4.4 - Java Class Libraries
  20.  
  21.  
  22.  
  23. 4.5 - Performance
  24.  
  25.  
  26.  
  27. 4.6 - The Java Language Compared
  28.  
  29.  
  30.  
  31. 4.7 - Summary
  32.  
  33.  
  34.  
  35. Programmers using "traditional" software development tools have become inured to the artificial
  36. edit-compile-link-load-throw-the-application-off-the-cliff-let-it-crash-and-start-all-over-again style of current development practice.
  37.  
  38. Additionally, keeping track of what must be recompiled when a declaration changes somewhere else is straining the capabilities of development tools--even fancy "make"-style tools such as are found on UNIX systems. This development approach bogs down as applications grow into the hundreds of thousands of lines of code sizes.
  39.  
  40. Better methods of fast and fearless prototyping and development are needed. The Java language environment is one of those better ways, because it's interpreted and dynamic.
  41.  
  42. As discussed in the previous chapter on architecture-neutrality, the Java compiler generates byte codes for the Java Virtual Machine. The notion of virtual interpreted machines is not new. But the Java language brings the concepts into the realm of secure, distributed, network-based systems.
  43.  
  44. The Java language virtual machine is a strictly defined virtual machine for which an interpreter must be available for each hardware architecture and operating system on which you wish to run Java language applications. Once you have the Java language interpreter and run-time support available on a given hardware and operating system platform, you can run any Java language application from anywhere.
  45.  
  46. The notion of a separate "link" phase after compilation is pretty well absent from the Java environment. Linking, which is actually the process of loading new classes by the Class Loader, is a more incremental and lightweight process. The concomitant speedup in your development cycle means that your development process can be much more rapid and exploratory, and because of the robust nature of the Java language and run-time system, you will catch bugs at a much earlier phase of the cycle.
  47.  
  48.  
  49. ----------------------------------------------------------------
  50.  
  51.  
  52. 4.1 Dynamic Loading and Binding
  53.  
  54. The Java language's portable and interpreted nature produces a highly dynamic and dynamically extensible system. The Java language was designed to adapt to evolving environments. Classes are linked in as required and can be downloaded from across networks. Incoming code is verified before being passed to the interpreter for execution. 
  55.  
  56. Object-oriented programming has become accepted as a means to solve at least a part of the "software crisis," by assisting encapsulation of data and corresponding procedures, and encouraging the re-use of code. Most programmers doing object-oriented development today adopted C++ as their language of choice. But C++ suffers from a somewhat serious problem that impedes its widespread use in the production and distribution of "software ICs." This defect is known as the fragile superclass problem.
  57.  
  58.  
  59.  
  60. The Fragile Superclass Problem
  61.  
  62. This problem arises as a side-effect of the way that C++ is usually implemented. Any time you add a new method or a new instance variable to a class, any and all classes that reference that class will require a re-compilation, or they'll break. Keeping track of the dependencies between class definitions and their clients has proved to be a fruitful source of programming error in C++, even with the help of "make"-like utilities.The fragile superclass issue is sometimes also referred to as the "constant re-compilation problem." You can avoid these problems in C++, but with extraordinary difficulty, and doing so effectively means not using any of the language's OO features directly. By avoiding the object-oriented features of C++, developers defeat the goal of re-usable "software ICs."
  63.  
  64.  
  65.  
  66. Solving the Fragile Superclass Problem
  67.  
  68. The Java language solves the fragile superclass problem in several stages. The Java compiler doesn't compile references down to numeric values--instead, it passes symbolic reference information through to the byte code verifier and the interpreter. The Java interpreter performs final name resolution once, when classes are being linked. Once the name is resolved, the reference is rewritten as a numeric offset, enabling the Java interpreter to run at full speed.
  69.  
  70. Finally, the storage layout of objects is not determined by the compiler. The layout of objects in memory is deferred to run time and determined by the interpreter. Updated classes with new instance variables or methods can be linked in without affecting existing code.
  71.  
  72. At the small expense of a name lookup the first time any name is encountered, the Java language eliminates the fragile superclass problem. Java programmers can use object-oriented programming techniques in a much more straightforward fashion without the constant recompilation burden engendered by C++. Libraries can freely add new methods and instance variables without any effect on their clients. Your life as a programmer is simpler.
  73.  
  74.  
  75.  
  76. Interfaces
  77.  
  78. The Java language implements the concept of an interface--a concept borrowed from Objective C and similar to a class. An interface is simply a specification of a collection of methods that an object responds to. An interface does not include any instance variables or implementations. You can import and use multiple interfaces in a flexible manner, thus providing the benefits of multiple inheritance without the inherent difficulties created by the usual rigid class inheritance structure.
  79.  
  80.  
  81.  
  82. Run Time Representations
  83.  
  84. Classes in the Java language have a run-time representation. There is a class named Class, instances of which contain run-time class definitions. If you're handed an object, you can find out what class it belongs to. In a C or C++ program, you may be handed a pointer to an object, but if you don't know what type of object it is, you have no way to find out. In the Java language, finding out based on the run-time type information is straightforward. 
  85.  
  86. It is also possible to look up the definition of a class given a string containing its name. This means that you can compute a data type name and have it easily dynamically-linked into the running system.
  87.  
  88.  
  89. ----------------------------------------------------------------
  90.  
  91.  
  92. 4.2 Security in the Java Environment
  93.  
  94. Security commands a high premium in the growing use of the Internet for products and services ranging from electronic distribution of software and multimedia content, to "digital cash". The area of security with which we're concerned here is how the Java compiler and run-time system restrict application programmers from creating subversive code. 
  95.  
  96. The Java language compiler and run-time system implement several layers of defense against potentially incorrect code. One of the Java compiler's primary lines of defense is its memory allocation and reference model. Simply put, Java does not have "pointers" in the traditional C and C++ sense--memory cells that contain the addresses of other memory cells.
  97.  
  98. Memory layout decisions are not made by the compiler, as they are in C and C++. Rather, memory layout is deferred to run-time, and will potentially differ depending on the characteristics of the hardware and software platforms on which the Java language system is executing. The Java interpreter references memory via symbolic "handles" that are resolved to real memory addresses at run time. Java programmers can't forge pointers to memory, because the memory allocation and referencing model is completely opaque to the programmer and controlled entirely by the underlying run-time system.
  99.  
  100. Very late binding of structures to memory means that programmers can't infer the physical memory layout of a class by looking at its declaration. By removing the C/C++ memory layout and pointer models, the Java language has eliminated the programmer's ability to get behind the scenes and manufacture pointers to memory. These features must be viewed as positive benefits rather than a restriction on the programmer, because they ultimately lead to more reliable and secure applications.
  101.  
  102.  
  103.  
  104. The Byte Code Verification Process
  105.  
  106. What about the concept of a "hostile compiler"? Although the Java compiler ensures that Java source code doesn't violate the safety rules, when an application such as the HotJava web browser imports a code fragment from anywhere, it doesn't actually know if code fragments follow the Java language rules for safety--the code may not have been produced by a known-to-be trustworthy Java compiler. In such a case, how is the Java run-time system on your machine to trust the incoming byte code stream? The answer is simple--it doesn't trust the incoming code, but subjects it to byte code verification.
  107.  
  108. The tests range from simple verification that the format of a code fragment is correct, to passing through a simple theorem prover to establish that the code fragment plays by the rules--that it doesn't forge pointers, it doesn't violate access restrictions, and it accesses objects as what they are (for example, that "InputStream" objects are always used as "InputStreams" and never as anything else). A language that is safe, plus run-time verification of generated code, establishes a base set of guarantees that interfaces cannot be violated.
  109.  
  110. The Byte Code Verifier
  111.  
  112. The last phase of the byte code loader is the verifier. It traverses the byte codes, constructs the type state information, and verifies the types of the parameters to all the byte code instructions.
  113.  
  114.  
  115.  
  116. The illustration shows the flow of data and control from Java language source code through the Java compiler, to the byte code verifier and hence on to the Java interpreter. The important issue is that the Java class loader and the byte code verifier make no assumptions about the primary source of the byte code stream--the code may have come from the local system, or it may have travelled halfway around the planet. The byte code verifier acts as a sort of gatekeeper. The byte code verifier ensures that the code passed to the Java interpreter is in a fit state to be executed and can run without fear of breaking the Java interpreter. Imported code is not allowed to execute by any means until after it has passed the verifier's tests. Once the verifier is done, a number of important properties are known:
  117.  
  118.  
  119.  
  120. ΓÇóThere are no operand stack overflows or underflows
  121.  
  122. ΓÇóThe types of the parameters of all byte code instructions are known to always be correct
  123.  
  124. ΓÇóNo illegal data conversions are done, like converting integers to pointers
  125.  
  126. ΓÇóObject field accesses are known to be legal--private or public or protected
  127.  
  128.  
  129.  
  130. While all this checking appears excruciatingly detailed, by the time the byte code verifier has done its work, the Java interpreter can proceed knowing that the code will run securely. Knowing these properties makes the Java interpreter much faster, because it doesn't have to check anything. There are no operand type checks and no stack overflow checks. The interpreter can thus function at full speed without compromising reliability.
  131.  
  132.  
  133.  
  134. Security Checks in the Class Loader
  135.  
  136. After incoming code has been vetted and determined clean by the byte code verifier, the next line of defense is the Java class loader. The environment seen by a thread of execution running Java byte codes can be visualized as a set of classes partitioned into separate name spaces. There is one name space for classes that come from the local file system, and a separate name space for each network source.
  137.  
  138. When a class is imported from across the network it is placed into the private name space associated with its origin. When a class references another class, it is first looked for in the name space for the local system (built-in classes), then in the name space of the referencing class. There is no way that an imported class can "spoof" a built-in class. Built-in classes can never accidentally reference classes in imported name spaces--they can only reference such classes explicitly. Similarly, classes imported from different places are separated from each other.
  139.  
  140.  
  141.  
  142. Security in the Java Networking Package
  143.  
  144. Java's networking package provides the interfaces to handle the various network protocols (FTP, HTTP, Telnet, and so on). This is your front line of defense at the network interface level. The networking package can be set up with configurable levels of paranoia. You can 
  145.  
  146.  
  147.  
  148. ΓÇóDisallow all network accesses 
  149.  
  150. ΓÇóAllow all network accesses 
  151.  
  152. ΓÇóAllow network accesses to only the hosts from which the code was imported 
  153.  
  154. ΓÇóAllow network accesses only outside the firewall if the code came from outside
  155.  
  156.  
  157.  
  158.  
  159. ----------------------------------------------------------------
  160.  
  161.  
  162. 4.3 Multithreading
  163.  
  164. Sophisticated computer users become impatient with the do-one-thing-at-a-time mindset of the average personal computer. Users perceive that their world is full of multiple events all happening at once, and they like to have their computers work the same way.
  165.  
  166. Unfortunately, writing programs that deal with many things happening at once can be much more difficult than writing in the conventional single-threaded C and C++ style. You can write multithreaded applications in languages such as C and C++, but the level of difficulty goes up by orders of magnitude, and even then there are no assurances that vendors' libraries are "thread safe".
  167.  
  168. The major problem with explicitly programmed thread support is that you can never be quite sure you have acquired the locks you need and released them again at the right time. If you return from a method prematurely, for instance, or if an exception is raised, for another instance, your lock has not been released--deadlock is the usual result.
  169.  
  170.  
  171.  
  172. Java Supports Threads at the Language Level
  173.  
  174. Built in support for threads provides Java programmers with a powerful tool to improve perceived interactive performance of graphical applications. If your application needs to run animations and play music while scrolling the page and downloading a text file from a server, multithreading is the way to obtain fast, lightweight concurrency within a single process space. Threads are sometimes also called lightweight processes or execution contexts. 
  175.  
  176. Threads are an essential keystone of the Java language. Threads are a class from which you can instantiate new Thread objects. The Thread class provides a rich collection of methods to start the thread, run the thread, stop the thread, and make enquiries about the thread's status.
  177.  
  178. Java thread support includes a sophisticated set of synchronization primitives based on the widely used monitor and condition variable paradigm introduced twenty years ago by C.A.R. Hoare and implemented in a production setting in Xerox PARC's Cedar/Mesa system. Integrating support for threads into the language makes them much easier to use and more robust. Much of the style of the Java language's integration of threads was modelled after Cedar and Mesa.
  179.  
  180. Java's threads are pre-emptive. If your applications are likely to be compute-intensive, you might consider how to give up control periodically to give other threads a chance to run. This will ensure better interactive response for graphical applications.
  181.  
  182.  
  183.  
  184. Integrated Thread Synchronization
  185.  
  186. The Java language supports multithreading at the language (syntactic) level and via support from its run-time system and thread objects. At the language level, methods within a class that are declared synchronized do not run concurrently. Such methods run under control of monitors to ensure that variables remain in a consistent state. Every class and instantiated object has its own monitor that comes into play if required.
  187.  
  188. Here are a couple of code fragments from the sorting demonstration in the HotJava web browser. The main points of interest are the two methods stop and startSort, which share a common variable called kicker (it kicks off the sort thread):
  189.  
  190.  
  191.  
  192.  
  193. public synchronized void stop() {
  194.     if (kicker != null) {
  195.         kicker.stop();
  196.         kicker = null;
  197.     }
  198. }
  199. private synchronized void startSort() { 
  200.     if (kicker == null || !kicker.isAlive()) {
  201.         kicker = new Thread(this);
  202.         kicker.start();
  203.     }
  204. }
  205.  
  206.  
  207.  
  208. The stop and startSort methods are declared to be synchronized--they can't run concurrently, enabling them to maintain consistent state in the shared kicker variable. When a synchronized method is entered, it acquires a monitor. The monitor precludes synchronized methods from running while any other such method is running in that thread instance. When a synchronized method returns by any means, its monitor is released. Other synchronized methods within the same object are now free to run.
  209.  
  210. If you are writing Java language applications, you should take care to implement your classes and methods so they're thread-safe, in the same way that the Java language run-time libraries are thread-safe. If you wish your objects to be thread-safe, any methods that may change the values of instance variables should be declared synchronized. This ensures that only one method can change the state of an object at any time. Java language monitors are re-entrant--a method can acquire the same monitor more than once, and everything will still work.
  211.  
  212.  
  213.  
  214. Multithreading Support--Conclusion
  215.  
  216. While other systems have provided facilities for multithreading (usually via "lightweight process" libraries), building multithreading support into the language as Java has done provides the programmer with a much more powerful tool for easily creating thread-safe multithreaded classes.
  217.  
  218. Other benefits of multithreading are better interactive responsiveness and real-time behavior. Stand-alone Java run-time environments exhibit good real-time behavior. Java environments running on top of popular operating systems provide the real-time responsiveness available from the underlying platform.
  219.  
  220.  
  221. ----------------------------------------------------------------
  222.  
  223. 4.4 Java Class Libraries
  224.  
  225. Java supplies extensive and well developed class libraries so programmers can get started quickly. 
  226.  
  227.  
  228.  
  229. Language Foundation Classes 
  230.  
  231. At the lowest level of the Java language, the foundation classes implement wrappers for the primitive types, threads, exceptions, and a variety of other fundamental classes.
  232.  
  233.  
  234.  
  235. I/O Class Library 
  236.  
  237. At the lowest level of the Java language, there are foundation classes that implement 
  238.  
  239.  
  240.  
  241. Another Window Toolkit Class Library 
  242.  
  243. The window toolkit library implements the functionality you need to display and interact with graphical user interface components on the screen. This library contains classes for the basic interface components, events, fonts, color, and controls such as buttons and scrollbars. 
  244.  
  245.  
  246.  
  247. Utility Class Library 
  248.  
  249. The utility class library implements a variety of encoder and decoder techniques, date and time, hash table, vector, and stack. 
  250.  
  251.  
  252.  
  253. Network Interface Class Library 
  254.  
  255. The network interface class library extends the functionality of the I/O class library with socket interfaces and Telnet interfaces. 
  256.  
  257.  
  258.  
  259.  
  260. ----------------------------------------------------------------
  261.  
  262.  
  263. 4.5 Performance
  264.  
  265. Test measurement of some simple Java programs on current high-end computer systems show results roughly as follows:
  266.  
  267. new Object 119,000 per second
  268. new C() (class with several methods) 89,000 per second
  269. o.f() (method f invoked on object o) 590,000 per second
  270. o.sf() (synchronized method f invoked on object o) 61,500 per second
  271.  
  272. While these performance numbers for interpreted byte codes are usually more than adequate to run interactive graphical end-user applications, situations may arise where higher performance is required. In such cases, the byte codes can be translated on the fly (at run-time) into machine code for the particular CPU on which the application is executing. For those accustomed to the normal design of a compiler and dynamic loader, this is somewhat like putting the final machine code generator in the dynamic loader.
  273.  
  274. The byte code format was designed with generating machine codes in mind, so the actual process of generating machine code is generally simple. Reasonably good code is produced: it does automatic register allocation and the compiler does some optimization when it produces the byte codes. Performance of byte codes converted to machine code is roughly the same as native C or C++. 
  275.  
  276.  
  277. ----------------------------------------------------------------
  278.  
  279.  
  280. 4.6 The Java Language Compared
  281.  
  282. Prospective adopters of the Java language need to examine where the Java language fits into the firmament of other languages. Here is a basic comparison chart illustrating the attributes of the Java language--simple, object-oriented, threaded, and so on--as described in the earlier parts of this paper.
  283.  
  284. From the diagram above, you see that the Java language has a wealth of attributes that can be highly beneficial to a wide variety of developers.
  285.  
  286. There are literally hundreds of programming languages available for developers to write programs to solve problems in specific areas. The programming languages cover a spectrum ranging across fully interpreted languages such as UNIX Shells, awk, TCL, Perl, and so on, all the way to "programming to the bare metal" languages like C and C++.
  287.  
  288. Languages at the level of Shells and TCL, for example, are fully interpreted high level languages. They deal with "objects" (at least in the sense they can be said to deal with objects at all) at the system level--their objects are files and processes rather than data structures. Some of these languages are suitable for very fast prototyping--you can develop your ideas quickly, try out new approaches, and discard non-working approaches without investing enormous amounts of time in the process. Scripting languages are also highly portable. Their primary drawback is performance--they are generally much slower than either native machine code or interpreted byte codes. This tradeoff may well be reasonable if the run time of such a program is reasonably short and you use the program on an itinerant basis.
  289.  
  290. At the lowest level are compiled languages such as C and C++, in which you can develop large-scale programming projects that will deliver high performance. The high performance comes at a cost, however. Drawbacks include the high cost of debugging non-robust memory management systems and difficult to implement and use multithreading capabilities. And of course when you use C++, you have the perennial fragile superclass issue. Last but definitely not least, the binary distribution problem of compiled code becomes unmanageable in the context of heterogeneous platforms all over the Internet.
  291.  
  292. The Java language environment creates an extremely attractive middle ground between the very high-level and portable but slow scripting languages and the very low level and fast but non-portable and unreliable compiled languages. The Java language fits somewhere in the middle of this space. In addition to being extremely simple to program, highly portable and architecture neutral, the Java language provides a level of performance that's entirely adequate for all but the most compute-intensive applications.
  293.  
  294.  
  295. ----------------------------------------------------------------
  296.  
  297.  
  298. 4.7 Summary
  299.  
  300. From the discussion above, you can see that the Java language provides high performance while its interpreted nature makes it the ideal development platform for fast and fearless prototyping. From the previous chapters, you've seen that the Java language is extremely simple and object oriented. The language is secure to survive in the network-based environment. The architecture-neutral and portable aspects of the Java language make it the ideal development language to meet the challenges of distributing dynamically extensible software across networks.
  301.  
  302.  
  303.  
  304. Now We Move On to the HotJava World-Wide Web Browser
  305.  
  306. These first four chapters have been your introduction to the Java language environment. You've learned about the capabilities of the Java language environment and its clear benefits to develop software for the distributed world. It's time to move on to the next chapter and take a look at the HotJava World-Wide Web browser--a major end-user application developed to make use of the dynamic features of the Java language environment.
  307.  
  308.  
  309.