PPT

Werbung
Java
Programmiersprachenkonzepte
Universität HH, SS 2004
29.04.2004
Kai Meyer & Torsten Witte
Inhalt
•
•
•
•
•
•
•
•
Ursprünge & Anwendungsgebiete
Funktionsweise von Java
Datentypen, Operatoren, Kontrollfluss
Vererbung, Polymorphie
Threads
RMI
Jini
JavaSpace
Ursprünge von Java
• 23. Mai 1995 Vorstellung von Java durch Sun
• Der Name stammt von einer in Amerika üblichen Bezeichnung für
Kaffee
• Einfache und kompakte, Objekt-orientierte und plattformunabhängige
Programmiersprache für Unix-Workstations, PCs und Apple, sowie
Micro-Computer in Haushalts- oder Industriegeräten
• Java ist für alle Computersysteme (im Allgemeinen kostenlos)
verfügbar
• Für kommerzielle Anwendungen muss man für die Compiler-Software
eine kostenpflichtige Lizenz erwerben
Anwendungsgebiete
•
Ursprünglich:
– Steuerung von Haushaltsgeräten und PDAs
•
Heute:
– Datenbanken
– Betriebssysteme
– Internet
– Web-Browser
– Unterhaltungselektronik
– Handys
– Haushaltsgeräte (Toaster, Mikrowelle, Kaffeemaschine,
Waschmaschinen, Videorekorder)
– Autos
– Verkehrsampeln
– Kreditkarten
– TV-Settop-Boxes für "intelligente" Fernsehapparate
– wissenschaftliche Programmierung
– usw.
Bytecode und JVM
•
•
•
Abstrakte Definition der Maschine, deren Verhalten von dem jeweiligen
ausführenden Rechner simuliert wird
Java-Compiler erzeugt plattformunabhängigen Bytecode
Der Bytecode kann auf jedem anderen Computersystem durch die Java Virtual
Machine (JVM) ausgeführt werden
Elementare Typen
• Ganzzahlige Typen:
byte
short
int
long
8 Bits
16 Bits
32 Bits
64 Bits
(byte)42
(short)42
42
42L
-128 bis 127
-32.768 bis 32.767
-2.147.483.648 bis 2.147.483.647
-9.223.372.036.854.775.808 bis
9.233.372.036.854.775.807
32 Bits
64 Bits
42.0F
42.0
-3.4*1038 bis 3.4*1038
-1.8*10308 bis 1.8*10308
16 Bits
‘A‘
Zeichen und Symbole
true
true, false
• Dezimaltypen:
float
double
• Zeichentyp:
char
• Logischer Typ:
boolean
Operatoren
• Zuweisung:
=
Zuweisung
• Vergleichsoperatoren für Zahlen und Zeichen:
==
!=
<
>
<=
>=
ist gleich
ist ungleich
ist kleiner als
ist größer als
ist kleiner oder gleich
ist größer oder gleich
• Logische Operatoren:
&&
||
!
und
oder
nicht
equals
ist gleich (bei Objekten)
Kontrollfluss (1)
• Bedingte Verzweigung:
if (Bedingung)
{Anweisung1; Anweisung2; ...}
else
{Anweisung1; Anweisung2; ...}
switch (variable)
{
case wert_1: Anweisung1; break;
case wert_2: Anweisung2; break;
...
default: Defaultanweisung; break;
}
Kontrollfluss (2)
• Schleifen:
for (Initialisierung; Ausdruck; Aktualisierung)
{Anweisung1; Anweisung2;...}
Beispiel:
for (int i=0; i<10; i++) {
System.out.println(i);
}
while (Bedingung)
// solange noch Bedingung
{Anweisung1; Anweisung2;...}
do
// solange bis Bedingung
{Anweisung1; Anweisung2;...}
while (Bedingung)
Vererbung
• (Unter-)Klassen können Operationen von anderen (Ober-)Klassen
–
–
–
–
implementieren (falls dies nicht in der Oberklasse geschehen ist),
redefinieren (verdecken, überschreiben),
erben, oder
neue Operationen hinzufügen
• In Java ist nur Einfachvererbung zwischen Klassen möglich:
Oberklasse:
Unterklassen:
Polymorphie
•
•
•
Objekte einer Unterklasse können an Bezeichner gebunden werden, die mit dem Typ
der Oberklasse deklariert sind
Dies kann durch Zuweisung oder durch Parameterübergabe geschehen
Beispiel:
public class Oberklasse {...}
public class Unterklasse extends Oberklasse {...}
public class KlasseX {
public void setY(Oberklasse y) {...}
}
Unterklasse _unterklassenbezeichner = new Unterklasse();
Oberklasse _oberklassenbezeichner;
_oberklassenbezeichner = _unterklassenbezeichner;
// Zuweisung
KlasseX _x = new KlasseX();
_x.setY(_unterklassenbezeichner);
// Parameterübergabe
Threads
• Java unterstützt die nebenläufige Programmierung direkt
• Das Konzept beruht auf so genannten Threads (zu Deutsch
»Faden« oder »Ausführungsstrang«), das sind parallel ablaufende
Aktivitäten, die sehr schnell in der Umschaltung sind
• Threads können vom Scheduler sehr viel schneller umgeschaltet
werden als Prozesse, sodass wenig Laufzeitverlust entsteht
• Threads werden entweder direkt von dem Betriebssystem unterstützt
oder von der virtuellen Maschine simuliert
• Die Integration in die Sprache macht das Entwerfen nebenläufiger
Anwendungen in Java einfacher
• Java realisiert gegenseitigen Ausschluss von Methoden verschiedener
Threads, Methoden gleicher Threads schließen sich nicht aus
Implementation von Threads
Variante 1
•
Threads über die Schnittestelle Runnable implementieren:
Z.B. zwei Threads, wobei einer zwanzigmal das aktuelle Datum und die Uhrzeit ausgibt
und der andere einfach eine Zahl.
class DateThread implements Runnable {
public void run() {
for ( int i=0; i<20; i++ )
System.out.println( new Date() );
}
}
class CounterThread implements Runnable {
public void run() {
for ( int i=0; i<20; i++ ) {
System.out.println( i ); }
}
}
Implementation von Threads
Variante 1
•
•
Direkter Aufruf von run()  Sequenzielle Ausführung des Codes
Parallele Ausführung:
1.) Erzeugung eines Thread-Objekts
2.) Aufruf von start()
public class FirstThread {
public static void main( String args[] ) {
Thread t1 = new Thread( new DateThread() );
t1.start();
Thread t2 = new Thread( new CounterThread() );
t2.start();
}
}
•
Nachdem start() für den Thread eine Ablaufumgebung geschaffen hat, ruft es dann
selbstständig die Methode run() genau einmal auf. Läuft der Thread schon, so wirft die
start()-Methode eine IllegalThreadStateException
Implementation von Threads
Variante 2
•
Die Klasse Thread erweitern:
Beispiel:
class DateThreadExtends extends Thread {
public void run() {
for ( int i=0; i<20; i++ )
System.out.println( new Date() );
}
}
Der Thread startet wieder beim Aufruf von start():
Thread t = new DateThreadExtends();
t.start();
Oder auch ohne Zwischenspeicherung der Objektreferenz:
new DateThreadExtends().start();
Gegenüberstellung der beiden
Implementationen
Vorteil
Nachteil
Ableiten von Thread
(extends Thread)
Programmcode in run()
kann die Methoden der
Klasse Thread nutzen
Da es in Java keine
Mehrfachvererbung gibt,
kann die Klasse nur Thread
erweitern
Implementieren von
Runnable
(implements
Runnable)
Die Klasse kann von einer
anderen,
problemspezifischen Klasse
erben
Kann sich nur mit Umwegen
selbst starten; allgemein:
Thread-Methoden können
nur über Umwege genutzt
werden
Threads beenden
Allgemein ist ein Thread beendet, wenn eine der folgenden Bedingungen zutrifft:
• Die run()-Methode wurde ohne Fehler beendet. Wenn wir eine
Endlosschleife programmieren, würde diese dann potenziell einen nie endenden
Thread bilden.
• In der run()-Methode tritt eine Exception auf, die die Methode beendet.
• Der Thread wurde von außen abgebrochen. Dazu dient die prinzipbedingt
problematische Methode stop(), von deren Verwendung abgeraten wird und
die auch veraltet ist.
Besser, z.B. wenn Thread eine Endlosschleife enthält:
Mit der Methode interrupt() von außen in einem Thread-Objekt ein
internes Flag setzen, welches dann in der Endlosschleife (in der run()Methode) durch isInterrupted() periodisch abgefragt wird und falls
diese true liefert mit break die Schleife verlassen und so den Thread ohne
Fehler terminieren lassen
Zustände von Threads
•
feststellbare Zustände:
- nicht erzeugt
- laufend (vom Scheduler berücksichtigt)
- nicht laufend (vom Scheduler nicht berücksichtigt)
- wartend
- beendet
Lebenszyklus von Java-Threads
Synchron oder Asynchron ?
•
•
•
Nebenläufige Threads arbeiten asynchron
Man kann jedoch mit der Methode join() auf das Ende der Aktivität eines Threads warten
Beispiel:
class JoinTheThread
{
static class JoinerThread extends Thread {
public int result;
public void run() {
result = 1;
}
}
public static void main( String args[] ) throws Exception {
JoinerThread t = new JoinerThread();
t.start();
t.join();
// hier wird gewartet bis t fertig ist
System.out.println( t.result );
}
}
Synchronisation mit „synchronized“
•
•
•
•
Problem: mehrere Threads wollen (gleichzeitig) auf gemeinsamen Daten schreiben
Folge: inkonsistente Daten
Lösung: zusammenhängende Programmblöcke, die nicht unterbrochen werden dürfen
(kritische Abschnitte + gegenseitigen Ausschluss), ABER: Gefahr von Verklemmungen!
Beispiel: Ein Zähler der von mehreren Threads heraufgezählt wird:
public class Counter {
static int counter = 0;
private static Counter _counter=null;
private Counter() {}
public static Counter getInstance() {
if (_counter==null) {_counter = new Counter();}
return _counter;
}
public int get_counter() {
return counter;
}
public synchronized void inc_counter() {
counter++;
<- ist nicht atomar!!!
}
}
Synchronisation über Warten und
Benachrichtigen
public class Fernseher {
public Fernseher() {}
public boolean is_sport() {...}
}
public class Frau extends Thread {
public void run() {
synchronized(_fernseher) {
_fernseher.wait();
// Sportschau fängt an!
}
}
}
public class Mann extends Thread {
public void run() {
synchronized(_fernseher) {
while (!_fernseher.is_sport()) {}
_fernseher.notify();
}
}
}
Class java.lang.Thread
(Methoden) (1)
•
•
•
•
•
•
•
•
•
•
•
•
void start()
ein neuer Thread, neben dem die Methode aufrufenden Thread, wird
gestartet. Der neue Thread führt die run()-Methode nebenläufig aus.
void run()
diese Methode enthält den parallel auszuführenden Programmcode
boolean isAlive()
liefert true, wenn der Thread gestartet und noch nicht terminiert ist
void sleep(long millis, int nanos) der aktuell ausgeführte Thread wird mindestens millis Millisekunden
und zusätzlich nanos Nanosekunden eingeschläfert.
void yield()
zwingt den aktuell ausgeführten Thread zu pausieren und erlaubt die
Weiterführung anderer Threads
void wait()
der aktuelle Thread wartet an dem aufrufenden Objekt darauf, dass er
nach einem notify() weiterarbeiten kann
void notify()
weckt einen beliebigen Thread auf, der an diesem Objekt wartet
void notifyAll()
weckt alle Threads auf, die an diesem Objekt warten
void join()
der aktuell ausgeführte Thread wartet auf den Thread, für den die
Methode aufgerufen wird, bis dieser beendet ist
void interrupt()
setzt in einem (anderen) Thread-Objekt ein Flag, um den Thread zu beenden
boolean isInterrupted()
fragt das Flag ab
boolean interrupted()
testet das entsprechende Flag des aktuell laufenden Threads, und
modifiziert es auch, sodass es danach gelöscht ist
Class java.lang.Thread
(Methoden) (2)
Seit JDK 1.2 verworfen und als „deprecated“ eingestuft:
– void suspend() blockiert den Thread
– void resume() de-blockiert den Thread
– void stop()
beendet den Thread
Remote Method Invocation (RMI)
• RMI ist für Java der Mechanismus, um entfernte Objekte und dessen
Angebote zu nutzen
• RMI (Java) steht im Gegensatz zu dem komplexen CORBA
(unterschiedliche Programmiersprachen)
• Anpassung von RMI an den defacto Standard CORBA
• Somit lässt sich auch über RMI eine Verbindung zwischen JavaProgrammen und nicht Java-Programmen herstellen.
CORBA
• CORBA steht für Common Object Request Broker
Architecture
• Entwickelt von der Object Management Group (OMG)
• Beruht in seinen Grundzügen auf der vom Remote
Procedure Call bekannten Technik
• Standardisierung von Object Request Broker (ORB)
• ORB ist die Basiskomponente der Kommunikation in
verteilten Anwendungen. Er dient dazu, Client/ServerBeziehungen zwischen Objekten aufzubauen.
• CORBA verfügbar u.a. in C, C++, Java, COBOL,
Smalltalk, Ada, Lisp, Python.
Vergleich zwischen CORBA und
RMI
• Viele Ähnlichkeiten in Architektur und
Prinzip zwischen RMI und CORBA
• Beide bieten Mechaniken wie Garbage
Collection, Interface Beschreibung und
Naming Service
• RMI wurde speziell für Java zugeschnitten,
daher Anschein eines abgespeckten
CORBAs
Vor- und Nachteile
• Vorteile zu CORBA
–
–
–
–
Transparenz
einfache Programmierung
eingebunden in JAVA JDK
URL basierte Namensgebung
• Nachteile zu CORBA
–
–
–
–
–
auf JAVA beschränkt, d.h. nicht so mächtig
proprietäres Protokoll
Geschwindigkeitsnachteil
wenige Services implementiert (auch nicht vorgesehen)
proprietärer Weg im Gegensatz zu standardisierten CORBA
Funktionsweise von RMI
• Der Server stellt das entfernte Objekt mit der Funktion bereit. Die
Funktion läuft im eigenen Adressraum, und der Server leitet Anfragen
an diese Funktion weiter.
• Eine Schnittstelle spezifiziert die von den entfernten Objekten
bereitgestellten Methoden.
• Die Methoden der Schnittstelle müssen dann implementiert werden.
• Der RMI-Compiler „rmic“ von Java generiert die Stubs und Skeletons.
• Über den Namendienst (Registry) melden die Server ihre entfernten
Objekte mit einem Namen an.
• Der Client holt sich über die Registry das Objekt mit der gewünschten
Methode.
Die Schnittstelle
import java.rmi.*;
public interface Adder extends Remote
{
public int add(int x, int y) throws RemoteException;
}
•
•
Übergabe von primitiven Parametern unproblematisch
Übergabe von serialisierbaren Objekten unproblematisch, falls Klassen beiden
Seiten bekannt sind, sonst müssen diese Klassen über den RMI-Klassenlader
nachgeladen werden.
Die Implementation
import java.rmi.*;
import java.rmi.server.*;
public class AdderImpl extends UnicastRemoteObject
implements Adder
{
public AdderImpl() throws RemoteException {
}
public int add( int x, int y ) throws
RemoteException
{
return x + y;
}
}
RMIC
Stubs und Skeletons (1)
• Stubs ist der Stellvertreter für den Server auf der Client-Seite
• Skeletons ist der Stellvertreters des Clients auf der Server-Seite
• Sind die Objekte die wirklich die Kommunikation betreiben
Stubs und Skeletons (2)
•
•
•
•
1. Schicht: Kommunikationspartner für Client und Server
2. Schicht: Regelt die korrekte Ausführung der Operationen
3. Schicht: Regelt die Netzkommunikation
4. Schicht: (Internet-)Verbindungsprotokolle
Der Server
import
import
import
import
java.net.*;
java.rmi.*;
java.rmi.server.*;
java.rmi.registry.*;
public class AdderServer {
public static void main( String args[] )
throws Exception {
AdderImpl adder = new AdderImpl();
Naming.rebind( "Adder", adder );
System.out.println( "Adder bound" );
}
}
Der Client
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
public class AdderClient {
public static void main( String args[] ) {
try {
Adder a=(Adder)Naming.lookup("Adder");
int sum = a.add( 2, 2 );
System.out.println( sum );
}
catch (Exception e) {System.out.println( e );}
}
}
RMI-Methoden
•
•
•
•
•
•
•
protected UnicastRemoteObject()
Erzeugt und exportiert ein neues UnicastRemoteObject und bindet es an einen
unbekannten Port.
static RemoteStub exportObject( Remote obj )
Exportiert das entfernte Objekt und macht es empfänglich für einkommende Aufrufe. Es wird
ein willkürlicher Port verwendet.
static void bind( String name, Remote obj )
Bindet den Stub, an den Namen name und trägt es so in der Registrierung ein.
static void rebind( String name, Remote obj )
Wie bind(), nur dass Objekte ersetzt werden, falls sie schon angemeldet sind.
static void unbind( String name )
Entfernt das Objekt aus der Registrierung.
static Remote lookup( String name )
Liefert eine Referenz auf den Stub, der mit dem entfernten Objekt name verbunden ist.
static String[] list( String name )
Liefert ein Feld mit angemeldeten Diensten. Der angegebene Name gibt die URL des
Namensdienstes an.
Jini Java Intelligence Network
Infrastructure
•
•
•
•
•
•
•
Offiziell wurde Jini am 25. Januar 1999 von Sun Microsystems vorgestellt
Erweiterung der Java-Plattform (Java 2)
Netzwerktechnologie, die es ermöglicht,
– Ressourcen im Netzwerk dynamisch zu verwalten
– Auffinden von Diensten zu regeln
– Geräte untereinander zu verknüpfen
Hauptmerkmale von Jini:
– Plattform-Unabhängigkeit
– nur Dienste (Services)
– keine Unterscheidung zwischen Hard- und Software
– Jini kann selbst Basis für weitere Netzdienste (wie JavaSpaces) sein
Infrastruktur: drahtgebunden oder drahtlos
Kommunikation: beliebiges Protokoll, standardmässig: RMI
Jini erweitert die Idee hinter RMI so, dass ein Ort zur Verfügung gestellt wird, an dem
die Objekte ihre Services anbieten oder andere Services finden können
Funktionsweise von Jini
•
•
•
•
In einem Jini-Netzwerk gibt es drei verschiedene Gruppen:
–
Dienst,
–
Client,
–
Lookup-Service
Ein Service muss sich im Lookup Service registrieren
Ein Client sucht einen Service (Dienst) über den Lookup Service
Beide müssen allerdings zuerst den Lookup Service finden. Das
geschieht über das Discovery.
Grundkonzepte von Jini
•
•
•
•
•
Discovery: das Finden von Communities im Netz und deren Verbindung
untereinander (als spontane Community-Bildung)
Lookup: diese Rolle des Directoryservices in der Jini-Community ist das
Suchen und Finden von Diensten unter Berücksichtigung der Typenhierarchie
und Vererbungsrelation
Leasing: dieses Konzept impliziert die sogenannte Selbstheilungsfähigkeit im
Jini und bedeutet, daß nach einem möglichen Ausfall von Diensten das
Recover gesteuert wird und das Wachstum nicht benötigter Dienste in Grenzen
gehalten wird (vgl. Garbage Collection)
Remote Events: das bedeutet, daß die Dienste einander Mitteilungen über ihre
Statusänderungen machen können (jede Jini-Komponente kann im Prinzip alle
(anderen) Events empfangen)
Transactions: hierbei geht es um die sichere Realisierung von Transaktionen,
die eine verteilte Ausführung letztendlich erfordert
JavaSpaces (1)
• JavaSpaces basiert auf der Jini-Technologie (spezieller Jini-Service)
• Entstanden aus den „Tuple-Spaces“ von „Linda“
• Ein Space ist ein fortdauerndes Objekt-Lager, das von verschiedenen
Prozessen gemeinsam genutzt wird und über das Netzwerk zugänglich
ist
• Prozesse kooperieren, indem Objekte (Entrys) Spaces betreten und
wieder verlassen
• Dadurch nur schwach mit einander verbundene Prozesse
• Jegliche Kommunikation, sowie die - besonders bei verteilten
Systemen - schwierige Synchronisation der Aktivitäten geschieht mit
Hilfe des Space
JavaSpaces (2)
•
Die Prozesse führen drei einfache Operationen aus:
– write: Objekte in den Space schreiben
– read / readIfExists : Objekte, die sich im Space befinden, lesen
– take / takeIfExists: Objekte aus dem Space herausnehmen
Das „Hello World“ - Beispiel
import net.jini.core.lease.Lease;
import net.jini.space.JavaSpace;
public class HelloWorld {
public static void main(String[] args) {
try {
Message msg = new Message();
msg.content = "Hello World";
JavaSpace space = SpaceAccessor.getSpace();
space.write(msg, null, Lease.FOREVER);
Message template = new Message();
Message result = (Message)space.read(template, null,
Long.MAX_VALUE);
System.out.println(result.content);
} catch (Exception e) {e.printStackTrace();}
}
}
Quellen
• Vorlesungen P2 / P3
• Galileo- Openbook:
http://www.galileocomputing.de/openbook/javainsel/
• Java-API:
http://java.sun.com
Weitere Quellen:
• http://www.heise.de/ix/artikel/1998/11/166/
• http://www.thomasgraf.net/rmi/rmi2.htm
• u.a.
Fragen ?
Herunterladen