5.1 Grundlegende Arbeitsweise eines Applets
Applets sind Java-Programme, die auf einem Internet / Intranet-Server gespeichert sind. Sie werden auf verschiedene Client-Plattformen heruntergeladen und dort in einer Java Virtual Machine (JVM) ausgeführt, die von dem auf dem Client-Rechner ausgeführten Browser bereitgestellt wird.
Um ein Applet in einer Webseite zu integrieren benötigt man ein sogenanntes <APPLET>-Tag. In diesem <APPLET>-Tag stehen Informationen, die die JVM benötigt, um das Applet auszuführen.
Bevor das Applet gestartet wird prüft das Klassenlademodul in der JVM welche Klassen benötigt werden. Beim Klassenladevorgang werden die Klassendateien überprüft um sicher zu sein, daß es sich um gültige Klassendateien und nicht um bösartigen Code handelt. Ist der Klassenladevorgang erfolgreich abgeschlossen wird das Applet ausgeführt.
Benutzer, die ein Programm aus dem Internet herunterladen und ausführen, wollen sicher sein, daß dieses Programm keine bösartigen Aktionen ausführt wie z. B. das Formatieren der Festplatte oder das Öffnen von Verbindungen für "nicht vertrauenswürdige" Rechner. Deshalb erfolgt die Verteilung und Ausführung unter Aufsicht eines Security Managers, der Applets daran hindern kann, Aufgaben auszuführen.
Da der Security Manager viele Aktivitäten, die bei einer "normalen" Anwendung selbstverständlich sind nicht zuläßt, muß der Entwickler eines Applets sich im Vorfeld Gedanken darüber machen, welche Einschränkungen der Security Manager verursacht.
Standardmäßig werden alle Applets als "nicht vertrauenswürdig" betrachtet und von bestimmten Aktivitäten ausgeschlossen. Dazu zählen:
Es gibt weitere Aktivitäten (z. B. die Ausführung von Programmen auf lokalen Systemen, um Zeit zu sparen), die für Anwendungsentwickler selbstverständlich, in Applets jedoch nicht erlaubt sind. In jedem brauchbaren Java-Buch werden die Einschränkungen und eventuelle Lösungen aufgelistet, denen Applets unterliegen. [JBulider3]
5.2 Eigenschaften des Beispiel Applets
Abb. 5.1: Screenshot von der Benutzeroberfläche des Beispiel Applets
Das Beispiel Applet in dieser
Diplomarbeit soll jedem Anwender zeigen, wie sich die
Synchronisation von Threads auswirkt. Zur besseren Übersicht
wurde der Programmcode, den die einzelnen Threads ausführen
einfach gehalten.
Bei diesem Applet hat man die Möglichkeit drei Zähler und eine
grafische Animation zu starten. Die drei Zähler des Applets und
die grafische Animation sind unterschiedlich realisiert worden.
Der 1. Zähler ( Counter genannt ) ist durch eine einfache Klasse mit dem Namen Counter implementiert worden. Diese Klasse wird nicht als Thread ausgeführt sondern als "normaler" Programmcode.
Der 2. Zähler ( Thread 1 genannt ) ist durch die Klasse CountingThread implementiert worden. Diese Klasse wurde jedoch von der Klasse Thread abgeleitet und die run() Methode mit dem Programmcode des Zählers überschrieben. Dieser Zähler wird daher als Thread ausgeführt.
Der 3. Zähler ( Thread 2 genannt ) ist durch die Klasse CountingThreadRunnable implementiert worden. Diese Klasse besitzt das Interface Runnable und die run() Methode wurde mit dem Programmcode des Zählers überschrieben. Dieser Zähler wird daher als Thread ausgeführt.
Die grafische Animation ( Thread 3 genannt ) ist durch die Klasse ImageCanvas implementiert worden. Diese Klasse wurde von der Klasse Canvas abgeleitet und besitzt das Interface Runnable und die run() Methode wurde mit dem Programmcode für die grafische Animation überschrieben. Die grafische Animation wird auch als Thread ausgeführt.
Thread 3 soll eine Belastung des
Systems verursachen, damit das Verhalten des Applets auch unter
verschiedenen Bedingungen beobachtet werden kann.
Die eventuelle Synchronisation findet, mit Ausnahme der
"Synchronisation durch Priorität", zwischen Thread 1
und Thread 2 statt.
Die Oberfläche des Applets kann in vier Hauptbereiche unterteilt werden :
Folgende Arten der Synchronisation können ausgewählt werden:
Zusätzlich zu diesen Bereichen findet man am unteren rechten Rand noch zwei Buttons. Der Button "Alle Threads anhalten" bzw. "Alle Threads weiterführen" dient dazu, alle laufenden Threads anzuhalten oder weiterzuführen, ohne das die Synchronisation unterbrochen wird. Jeder Thread arbeitet nach der Unterbrechung so weiter wie vorher. Der "RESET" Button versetzt die Threads und das Ausgabefeld wieder in den Startzustand.
Führt man das Applet im Browser
aus, wird die maximale Priorität der Threads vom System so
begrenzt, daß wichtige Systemprozesse weiter arbeiten können
und somit das System lauffähig bleibt (siehe Kapitel 2.6).
Wird das Applet in einem Appletviewer ausgeführt besteht diese
Begrenzung nicht. In so einem Fall kann die Priorität bis auf
das Maximum (Prioritätswert 10) eingestellt werden. Hierbei ist
darauf zu achten, daß die Lauffähigkeit des Systems bei der
Vergabe von zu hohen Prioritäten eingeschränkt oder sogar
gestoppt wird.
Die Klassen, Konstruktoren und Methoden des Beispiel Applets werden in diesem Kapitel genauer erläutert. Im Source-Code befinden sich zusätzliche Erläuterungen, so daß nicht alle Attribute der Klassen hier aufgelistet werden.
Auf eine zusätzliche Visualisierung durch UML (Unified Modeling Language) Diagramme, wie z.B. einem Klassendiagramm, wurde ebenfalls verzichtet.
Die Klasse Applet1 ist von der Klasse Applet abgeleitet und besitzt die Interfaces ActionListener und FocusListener. Diese Klasse erzeugt die Eingabemaske. Die Hauptkomponenten dieser Oberflächen sind die zahlreichen Eingabefelder (javax.swing.JTextField), Bezeichner für die Oberfläche (javax.swing.JLabel) und die Aktionsknöpfe (javax.swing.JButton).
Diese Komponenten werden hier nicht eingehender erläutert, da sie im Source-Code kommentiert sind.
Attribute:
private boolean sync Variable für Synchronisation durch Ereignisse. private boolean syncjoin Variable zur Synchronisation auf das Ende eines Threads. private CountingThread thread1 Objekt für Thread 1. private Thread thread2, thread3 Objekte für Thread 2 und Thread 3. private Runnable rthread, bthread Runnable Objekte für die Klassen mit dem Interface Runnable. private int[] thindex = new int [3] Thread Index um festzuhalten welcher Thread gestartet wurde. private String sleepthread1 private String sleepthread2 Variable um sleep-Zeit zu speichern, wenn durch Priorität synchronisiert wird. private Steuerung steuer = new Steuerung(false) Objekt um die Threads anzuhalten und wieder auszuführen. private Beenden stop2 = new Beenden(false) private Beenden stop3 = new Beenden(false) stop2 ist ein Objekt der Klasse Beenden und dient dazu dem Thread 2 anzuzeigen, das er seine run() Methode beenden soll. stop3 ist für Thread 3. private Syncprio syncprio Diese Objekt dient zur Synchronisation durch Priorität. private IntJTextField jTextFieldA[] = new IntJTextField[13] Feld für 13 Textfelder (Eingabefelder). MeineTextArea textArea1 Ausgabefeld für alle Threads und Zusatzinformationen. Methoden: public String getParameter(String key, String def) Parameterwert zum Starten des Applets holen. public Applet1() Das Applet konstruieren. public void init() Das Applet initialisieren. private void jbInit() Initialisierung der Komponenten. public String getAppletInfo() Applet-Informationen werden geholt. public String[][] getParameterInfo() Parameter-Infos holen. public static void main(String[] args) Main-Methode public void actionPerformed(ActionEvent e) ActionPerformed, der ausgeführt wird sobald ein Button betätigt wird. void thread1start() Eigene Methode um Thread 1 zu erzeugen und ggf. zu starten. void thread2start() Eigene Methode um Thread 2 zu erzeugen und ggf. zu starten. void jButton1_actionPerformed(ActionEvent e) Methode, die durch Betätigung eines Buttons ausgeführt wird, um die Priorität von Thread 1 herabzusetzen. void jButton2_actionPerformed(ActionEvent e) Methode, die durch Betätigung eines Buttons ausgeführt wird, um die Priorität von Thread 1 heraufzusetzen. void jButton3_actionPerformed(ActionEvent e) Methode, die durch Betätigung eines Buttons ausgeführt wird, um die Priorität von Thread 2 herabzusetzen. void jButton4_actionPerformed(ActionEvent e) Methode, die durch Betätigung eines Buttons ausgeführt wird, um die Priorität von Thread 2 heraufzusetzen. void jButton5_actionPerformed(ActionEvent e) Methode, die durch Betätigung eines Buttons ausgeführt wird, um die Priorität von Thread 3 herabzusetzen. void jButton6_actionPerformed(ActionEvent e) Methode, die durch Betätigung eines Buttons ausgeführt wird, um die Priorität von Thread 3 heraufzusetzen. public void focusLost(FocusEvent e) Methode des FocusListener wird ausgeführt sobald ein Objekt den Focus verliert. public void focusGained(FocusEvent e) Methode des FocusListener wird ausgeführt sobald ein Objekt den Focus erhält. public boolean test() Methode, die kontrolliert, ob alle Textfelder in ihrem Wertebereich sind. public void setsync() Diese Methode stellt fest ob die Ausgabe synchronisiert werden soll. void groupBox1_itemStateChanged(ItemEvent e) Methode wird ausgeführt, wenn durch Ereignisse synchronisiert werden soll. Sie setzt dann die entsprechenden Parameter. void groupBox2_itemStateChanged(ItemEvent e) Methode wir ausgeführt, wenn durch die Priorität synchronisiert werden soll. Sie setzt dann die entsprechenden Parameter. void groupBox3_itemStateChanged(ItemEvent e) Methode wird ausgeführt, wenn auf das Ende des zweiten Threads synchronisiert wird. Sie setzt dann die entsprechenden Parameter. void groupBox4_itemStateChanged(ItemEvent e) Methode wird ausgeführt, wenn nicht synchronisiert werden soll. Sie setzt dann die entsprechenden Parameter. void jTextFieldA11_actionPerformed(ActionEvent e) Methode wird ausgeführt, wenn eine Eingabe im Textfeld 11 erfolgte. Dieses Eingabefeld bestimmt die Anzahl der Ausgaben. void jTextFieldA12_actionPerformed(ActionEvent e) Methode wird ausgeführt, wenn eine Eingabe im Text Feld 12 erfolgte. Dieses Eingabefeld bestimmt die Anzahl der Schleifen. class Applet1_jTextFieldA11_actionAdapter implements java.awt.event.ActionListener Klasse des action_Adapter für das Eingabefeld 11 public void actionPerformed(ActionEvent e) Methode des action_Adapter für das Eingabefeld 11 class Applet1_jTextFieldA12_actionAdapter implements java.awt.event.ActionListener Klasse des action_Adapter für das Eingabefeld 12 public void actionPerformed(ActionEvent e) Methode des action_Adapter für das Eingabefeld 12
Diese Klasse dient dazu, die Thredas 2 und 3, die mit Hilfe des Interfaces Runnable erstellt wurden, zu beenden. Durch ein Objekt dieser Klasse können die beiden Threads "erfragen" ob sie sich beenden sollen.
Konstruktor:
public Beenden(boolean wert) Beim Erzeugen des Objekts muß der Anfangswert übergeben werden.
Attribut:
private boolean stop Speichert den Wert des Objektes.
Methoden:
public void set(boolean wert) Methode um den Wert des Objektes zu ändern. public boolean get() Methode um den Wert des Objektes abzufragen.
Diese Klasse ist ein Zähler, der einen übergebenen Wertebereich durchläuft.
Konstruktor:
public Counter(MeineTextArea textArea1) Beim Erzeugen wird die Text Area übergeben, auf die die Ausgabe erfolgen soll.
Attribute:
private int start Startwert des Zählers. private int finish Ende des Zählers. private long time Zeit, die der Zähler zwischen den Zählerschritten "schlafen" soll. MeineTextArea textArea1 TextArea für die Ausgabe.
Methode:
public void setcounter (int from, int to, long zeit) Daten für den Zähler werden übernommen und der Zähler wird ausgeführt.
5.3.4 Die Klasse CountingThread.java
Diese Klasse ist von Thread abgeleitet und beinhaltet einen Zähler, der somit als Thread ausgeführt wird.
Konstruktor:
public CountingThread(Syncprio syncprio,MeineTextArea textArea1, Steuerung steuer,JLabel jLabel12) Beim Erzeugen werden Objekte von anderen Klassen übergeben. Diese Objekte werden zur Steuerung und Ausgabe des Threads benötigt.
Attribute:
private int start private int finish private long time Variablen wie bei der Klasse Counter private boolean stop Variable für eigene "stop"-Methode des Threads MeineTextArea textArea1 TextArea für Ausgabe. Steuerung steuer Steuerobjekt zum Überprüfen, ob der Thread anhalten soll. Syncprio syncprio Steuerobjekt für Synchronisation durch Priorität. JLabel jLabel12 Ausgabefeld der Priorität
Methoden:
public void meinstop() Modifizierte "stop"-Methode. public void setcountingthread(int from, int to,long zeit) Methode um die Daten für den Zähler zu übernehmen.
public void joinset(Thread thread) Modifizierte "start"-Methode. Sie dient zum Starten, wenn auf das Ende eines andern Thread gewartet werden soll.
public void run() run() Methode des Threads.
5.3.5 Die Klasse CountingThreadRunnable.java
Diese Klasse beinhaltet ebenfalls ein Zähler. Sie besitzt das Interface Runnable wodurch der Programmcode ebenfalls als Thread ausgeführt wird.
Konstruktor:
public CountingThreadRunnable(JLabel jLabel13,Syncprio syncprio, Beenden stop2,Steuerung steuer, MeineTextArea textArea1, int from, int to,long zeit) Beim Erzeugen werden Objekte von anderen Klassen und die Daten für den Zähler übernommen. Die Objekte dienen der Steuerung und der Ausgabe des Zählers.
Attribute:
private int start private int finish private long time Variablen wie bei der Klasse Counter Beenden stop Objekt zum Beenden des Threads MeineTextArea textArea1 TextArea für Ausgabe. Steuerung steuer Steuerobjekt zum Überprüfen, ob der Thread anhalten soll. Syncprio syncprio Steuerobjekt für Synchronisation durch Priorität. JLabel jLabel13 Ausgabefeld der Priorität.
Methode:
public void run() run() Methode des Interfaces Runnable.
5.3.6 Die Klasse ImageCanvas.java
Diese Klasse ist abgeleitet von der Klasse Canvas und besitzt das Interface Runnable.Sie wird für die grafische Animation benötigt, die ebenfalls als Thread ausgeführt wird.
Konstruktor:
public ImageCanvas(Image images[],Steuerung steuer,Beenden stop3, Syncprio syncprio) Es wird ein Feld, das die Bilder enthält und Objekte anderer Klassen, übergeben.
Attribute:
private Image images[] Feld für die Bilder, die ausgegeben werden sollen. private int currentimage Variable für Bild. Beenden stop Objekt zum Beenden des Threads Steuerung steuer Steuerobjekt zum Überprüfen, ob der Thread anhalten soll. Syncprio syncprio Steuerobjekt für Synchronisation durch Priorität.
Methode:
public void paint(Graphics g) Methode zum Zeichnen des Bildes. public void update(Graphics g) Methode zum Zeichnen des Bildes. public void run() run() Methode des Interfaces Runnable.
5.3.7 Die Klasse IntJTextField.java
Diese Klasse ist abgeleitet von der Klasse JTextField.
Einige Methoden wurden ergänzt bzw. der Konstruktor so verändert, daß die Objekte Eingabefelder mit einem festen Wertebereich sind.
Konstruktor:
public IntJTextField (int min, int max) Konstruktor der Klasse dem beim Erzeugen des Objektes der erlaubte Wertebereich der Eingabe übergeben wird.
Attribute:
private int low Untere Grenze des Wertebereiches. private int high Obere Grenze des Wertebereiches
Methoden:
public boolean isValid() Methode um festzustellen, ob die Eingabe des Objektes ein Int-Wert im erlaubten Wertebereich ist. public int getValue() Methode zum Auslesen des Textfeldes.
5.3.8 Die Klasse MeineTextArea.java
Die Klasse ist von der Klasse TextArea abgeleitet und dient zur synchronisierten und nicht synchronisierten Ausgabe der Threads.
Konstruktor:
public MeineTextArea() Parameterloser Konstruktor
Attribute:
private String buffer Buffer für die Ausgabe. private int soll Anzahl der "soll" Ausgaben. private int anzahl Anzahl der "ist" Ausgaben boolean th1 Variable die bei einer Synchronisation durch Ereignisse angibt welcher Thread den Monitor erhält. boolean sync Variable die angibt ob eine Synchronisation durch Ereignisse stattfinden soll.
Methoden:
public void set(boolean syncronisieren,int anzahl) Methode zum Starten und Beenden der Synchronisation durch Ereignisse. public synchronized void put1 (String ausgabe) Synchronisierte Methode für die Ausgabe von Thread 1 public synchronized void put2 (String ausgabe) Synchronisierte Methode für die Ausgabe von Thread 2 public synchronized void put (String ausgabe) Synchronisierte Methode für die Ausgabe von allgemeinen Informationen.
5.3.9 Die Klasse Steuerung.java
Über ein Objekt dieser Klasse können die Threads angehalten und zu einem beliebigen Zeitpunkt weitergeführt werden.
Konstruktor:
public Steuerung(boolean wert) Beim Erzeugen des Objektes muß der Anfangswert übergeben werden.
Attribute:
private boolean halt Diese Variable zeigt an ob die Threads anhalten sollen oder nicht.
Methoden:
public void setanhalten () Methode um der Wert des Objektes auf true zu setzen. public synchronized void weiter() Methode um den Wert des Objektes auf false zu setzen. public synchronized void anhalten () Methode bei dessen Ausführung ein Thread angehalten wird, wenn das "Steuerugsobjekt" true ist.
5.3.10 Die Klasse Syncprio.java
Ob eine Synchronisation durch die Priorität stattfindet, wird durch ein Objekt dieser Klasse angezeigt. Die benötigten Schleifen um das System zu belasten gehören auch zu dieser Klasse.
Konstruktor:
public Syncprio(boolean wert, int schleifen) Die Schleifenzahl und ob eine Synchronisation durch die Priorität erfolgen soll wird beim Erzeugen festgelegt.
Attribute:
private boolean sync Zeigt an ob synchronisiert werden soll private int schleifen Gibt an wie oft die Threads die Methode "zeit()" aufrufen sollen.
Methoden:
public void setschleifen(int schleifen) Methode mit der die Schleifenzahl verändert werden kann. public int getschleifen() Methode über die die Schleifenzahl erfragt werden kann. public void setsync(boolean wert) Methode über die festgelegt wird ob eine Synchronisation durch die Priorität erfolgen soll oder nicht. public boolean getsync() Methode über die erfragt werden kann ob eine Synchronisation durch die Priorität erfolgen soll. public synchronized int zeit() Methode um bei einer Synchronisation durch die Priorität das System zu belasten.