Threads - Medieninformatik

Werbung
Prog. 2
9
•
Prog. 2
Threads
9
Ein Thread
•
Programm / Prozess
– ist ein eigenständiges Programmstück, das
parallel zu anderen Threads laufen kann
Threads in Java
Threads
– sind direkter Bestandteil der Sprache Java
A
– kann mit einem Prozeß verglichen werden,
läuft jedoch auf einer feineren Stufe ab
– sind immer Instanzen einer Klasse, die das Interface Runnable
implementiert
Ein Thread
• Runnable deklariert nur die (abstrakte) Methode void run()
• Ein Prozeß ist ein Instrument, um ein
komplettes Programm auszuführen
• run() enthält alle im Thread auszuführenden Anweisungen
• Instanzen von Klassen, die Runnable implementieren, heißen (Thread)-Targets
• Innerhalb eines Prozesses können mehrere
Threads parallel ablaufen
•
– kommunizieren durch
• Zugriff auf Instanz- oder Klassenvariablen
Alle Threads eines Programms
Programm / Prozess
• Aufruf von Methoden, die innerhalb von run() sichtbar sind
– teilen sich einen gemeinsamen Adressraum
• Adressräume von Prozessen sind streng
getrennt
A
B
Prog. 2
9
•
• Thread implementiert das Interface Runnable
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
• Jede Instanz von Thread (oder einer von Thread abgeleiteten Klasse)
ist Target eines Threads (kann als Thread ausgeführt werden)
1
Die Klasse Thread
9
Konstruktoren
•
Generischer Name
Thread-<nummer>
– public Thread(String name)
– public Thread(Runnable target, String name)
Thread-Target
– void run()
Enthält auszuführenden
Programmcode
– void start()
throws IllegalThreadStateException
Wenn Thread
schon gestartet
true wenn Thread
gestartet wurde
– finale boolean isAlive()
Gestartet wird ein Thread durch
den Aufruf von start()
– Anschließend wird die weitere
Ausführung automatisch an die
Methode run übertragen
• Würde wie ein normaler
Methodenaufruf aus dem
laufenden Thread behandelt
– final void setName()
final String getName()
– final void setPriority(int prio)
final int getPriority()
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
Zum Erzeugen eines Threads
muss
– Direkter Aufruf von run würde
keinen neuen Thread erzeugen
– static void sleep(long millis)
3
2
Erzeugen eines neuen Threads
– die Methode run()
überschrieben werden
•
Methoden
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
– eine Klassen von Thread
abgeleitet werden
Thread-Name
– public Thread(Runnable target)
18.06.2009
18.06.2009
Prog. 2
– public Thread()
•
C
Mehrere
Threads
– können auf gleiche Variablen zugreifen
18.06.2009
– werden gesteuert durch die Klasse Thread (aus java.lang.Thread)
18.06.2009
public class SimpleThread {
public static void main(String[] args) {
MyThread thread = new MyThread();
Out.println("Starting thread...");
thread.start();
try {
Thread.sleep(20);
} catch (InterruptedException e) {}
thread.stop(); // Deprecated!!!
Out.println("Thread has been
stopped!");
}
}
class MyThread extends Thread {
public void run() {
int counter=0;
while(true) {
Out.println(getName()+“:“+counter++);
}
}
}Programm-Ausgabe
Starting thread...
Thread-0: 1
Thread-0: 2
.
.
Thread-0: 321Thread has been stopped!
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
4
Prog. 2
9
•
Prog. 2
Beenden eines Threads
class MyStopThread extends Thread {
Ein Thread sollte nicht mit der Methode stop() beendet werden
}
//cancel = true;
thread.myStop();
Out.println("Thread has been stoped");
Out.print("Thread is alive: “);
public void run() {
Thread
thisThread=Thread.currentThread();
• Beendet die Methode run(), wenn die stopMyThread gleich true ist
int counter = 0;
– Damit sofort auf stop reagiert wird, muss
while (thread == thisThread) {
// while (!cancel) {
• entweder die Variable volatile sein, oder
Out.print(currentThread()+": “);
Mit dem Schlüsselwort volatile werden Variablen gekennzeichnet, die
asynchron (außerhalb des aktuellen Threads) modifizierbar sein sollen.
Out.println(counter++);
}
}
• der Zugriff auf die Variable synchronisiert sein.
}
5
18.06.2009
Out.println(thread.isAlive());
}
}
Programm-Ausgabe (Beispiel)
Starting thread...
Thread[Thread-0,5,main]: 1
.
.
Thread[Thread-0,5,main]: 59
Thread has been stoped
Thread is alive:true
Thread[Thread-0,5,main]: 60
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
6
Prog. 2
Unterbrechungsanforderungen
9
Beispiel (interrupt und isInterrupted)
public class ThreadInterrupt {
public static void main(String[] args) {
MyInterruptThread thread = new
MyInterruptThread();
System.out.println("Starting thread...");
thread.start();
try { Thread.sleep(100); }
catch (InterruptedException e) {}
System.out.println("isAlive: “+thread.isAlive());
thread.interrupt();
System.out.println("isAlive: “+thread.isAlive());
}
Abbruchflag wird zurückgesetzt
}
class MyInterruptThread extends Thread {
Programm-Ausgabe
public void run() {
Starting thread...
int counter = 0;
0
while (true) {
1
if (isInterrupted()) break;
2
try { Thread.sleep(10); }
3
4
catch (InterruptedException e) {
5
System.out.println(e);
isAlive: true
interrupt();
6
}
Java.lang.InterruptedException: sleep interrupted
7
System.out.println(counter++);
isAlive: false
}
Das richtige Mass für die Abfragehäufigkeit des „Stop-Flags“ ist in der
Praxis schwierig zu finden
– Wird „Stop-Flag“ zu oft abgefragt, werden unnötig Ressourcen verbraucht
– Wird „Stop-Flag“ zu selten abgefragt, ist die Zeit bis zum Stop zu lang
•
Thread.sleep(20);
} catch (InterruptedException e) {
}
• überprüft die Variable stopMyThread regelmässig
•
try {
thread = null;
– Target Thread
9
thread.start();
public void myStop() {
– Variable z.B. boolean stopMyThread zeigt an, ob Thread stoppen soll
Prog. 2
Out.println("Starting thread...");
überschrieben werden da sie final ist
*/
http://java.sun.com/docs/books/tutorial/essential/threads/
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
MyStopThread thread = new
MyStopThread();
/* Die Methode stop() kann nicht
http://java.sun.com/j2se/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html
18.06.2009
public static void main(String[] args) {
//private volatile boolean cancel = false;
Threads am besten durch Verwendung eines Flags beenden
–
public class MyStopThreadExample {
private volatile Thread thread = this;
– Es ist nicht definiert und auch nicht voraussagbar, wann der Thread
beendet wird
•
Beispiel
9
Die Klasse Thread stellt hierfür folgende Methoden zur Verfügung
– public void interrupt()
• Setzt ein (Abbruch-)Flag, das eine Unterbrechungsanforderung signalisiert
– public boolean isInterrupted()
• Liefert true, wenn das Abbruch-Flag gesetzt ist
– public static boolean interrupted()
• Liefert den Status des Abbruch-Flags beim aktuellen Thread
• Entspricht dem Aufruf von currentThread().isInterrupted() und
anschließendem Zurücksetzen des Abbruchflags auf initialen Wert false
}
18.06.2009
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
7
18.06.2009
}
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
8
Prog. 2
9
•
Prog. 2
Die Methode sleep
9
•
Mit Hilfe der folgenden Methoden kann ein Thread pausieren
Nicht alle Klassen, die als Thread laufen sollen, können von Thread
abgeleitet werden
– public static void sleep(long millis)
– Ist eine Klasse schon Bestandteil einer Vererbungshierarchie, kann sie nicht
mehr von Thread abgeleitet werden (keine Mehrfachvererbung in Java)
Aktueller Prozeß wird für millis Millisekunden angehalten
– public static void sleep(long millis, int nanos)
•
Aktueller Prozeß wird für millis Millisekunden und nanos Nanosekunden
angehalten
Anstatt einen Thread durch Ableiten der Klasse Thread, kann man ihn
auch durch Implementieren der Interfaces Runnable erzeugen
– Das Interface Runnable enthält nur eine einzige Methode
Tatsächliche Genauigkeit hängt von der Zielarchitektur ab
•
public abstract void run()
– Unter Windows ist es etwa 1ms
•
– sleep muss in einem try-catch Block gekapselt werden (kann während
der Wartezeit eine Ausnahme vom Typ InterruptedException auslösen)
Jede Klasse, deren Instanzen als Thread laufen sollen muss das
Interface Runnable implementieren (auch Thread selbst)
•
Um eine Instanz einer Klasse die Runnable implementiert als Thread
laufen zu lassen muss man
Beim Starten eines Java-Programms wird automatisch ein Thread für
die Ausführung des Hauptprogramms angelegt
– Ein neues Thread-Objekt erzeugen
18.06.2009
9
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
9
18.06.2009
Prog. 2
9
public class RunnableExample {
int counter;
class B
extends A
implements Runnable {
B Kann nicht von
Thread abgeleitet
werden
public class CountThread {
public static void main(String[] args) {
public Count(long maxNumber) {
B b = new B();
Count c = new Count(10);
this.maxNumber = maxNumber;
Thread thread = new Thread(b);
10
Wo ist der Fehler?
long maxNumber;
Instanz von B soll als Thread laufen
t.start();
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
class Count extends Thread {
public static void main(String[] args) {
}
Thread t = new Thread(c);
– Die Methode start() von Thread aufrufen
Runnable (Beispiel)
class A {
C c = new C();
• Konstruktor erhält Thread-Target
– Die Methode sleep kann somit auch dazu verwendet werden das
Hauptprogramm pausieren zu lassen
Prog. 2
Das Interface Runnable
c.start();
}
new Thread(c).start();
public void run() {
System.out.println("Starting thread...");
public void run() {
counter = 0;
thread.start();
while(true) {
if (Thread.interrupted()) {
Ruft die run-Methode
der Klasse B auf
for(long i=0; i<=maxNumber; i++)
Count2 c2 = new Count2(10);
System.out.println("Int Count: "+i);
c2.start();
}
new Thread(c2).start();
}
}
try {
break;
}
Thread.sleep(200);
class Count2 implements Runnable {
}
} catch (InterruptedException e) {}
long maxNumber;
System.out.println(counter++);
thread.interrupt();
public Count2(long maxNumber) {
}
System.out.
println("Thread has been stopped");
}
this.maxNumber = maxNumber;
}
}
}
Geht nicht da Count2 keine
Methode start() kennt
public void run() {
}
for (long i=0; i<=maxNumber; i++)
System.out.println("Int Count2: "+i);
}
}
18.06.2009
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
11
18.06.2009
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
12
Prog. 2
9
Prog. 2
Synchronisationsprobleme
class T1 extends Thread{
9
•
class Person {
Person p;
String name;
public T1(Person p) {
String surname;
this.p = p;
•
public void setName(String n, String s) {
}
name = n;
public void run() {
surname = s;
System.out.println(p.getName());
}
}
public String getName() {
}
return name + " " + surname;
Synchronisation mittels synchronized
Um Threads zu synchronisieren
gibt es in Java das Konzept des
Monitors
Ein Monitor kapselt einen
kritischen Bereich (Programmteil,
der nur von einem Programmteil auf
einmal durchlaufen werden darf) mit
Hilfe einer automatischen Sperre
Person p;
Person p = new Person();
}
T1 t1 = new T1(p);
public void run() {
T2 t2 = new T2(p);
t1.start();
}
}
}
Mögliche Programmausgaben
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
Synchronisation von Methoden
9
class Output {
int number;
static synchronized void printRow(int number){
public static void main(String[] args) {
•
for (int i = 0; i < 10; i++) {
Thread thread1 = new SyncedFuncThread(10);
int n = 0;
thread1.start();
double w;
thread2.start();
}
Thread.sleep(2000);
•
System.out.println();
} catch (InterruptedException e) {}
public void run() {
while (true) {
synchronized(getClass()){
Mehrere
Instanzen
von
SyncedThread
System.out.println(counter++);
}
}
}
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
14
Animation
Eine Animation ist das aufeinanderfolgende Anzeigen einer Sequenz
von Einzelbildern
Probleme bei der Animation
– Einzelbilder müssen im richtigen Timing angezeigt werden
}
thread1.stop();
}
thread2.stop();
}
• Zu wenig Bilder pro Zeiteinheit führen zu „ruckelnder“ Animation
Ohne synchronized
public SyncedFuncThread(int n) {
number = n;
}
public void run() {
for (int i = 0; i < 10; i++)
Output.printRow(number);
18.06.2009
thread2.stop();
}
while (n < 10000) w = Math.sqrt(n++);
try {
}
thread1.stop();
– Trägheit des menschlichen Auges sorgt für die Illusion einer
zusammenhängenden Bewegung
System.out.print(number + " ");
Thread thread2 = new SyncedFuncThread(20);
}
Thread.sleep(1000);
} catch (InterruptedException e) {}
Das Monitor-Konzept wird in Java
durch das Schlüsselwort
synchronized realisiert
18.06.2009
Prog. 2
public class SyncedFuncThread extends Thread {
try {
}
13
Prog. 2
9
thread2.start();
– Es kann eine komplette Methode
oder ein Block innerhalb einer
Methode geschützt werden
Peter Barth
Wolfgang Weitz
Peter Weitz
Wolfgang Barth
}
18.06.2009
•
t2.start();
p.setName("Wolfgang","Weitz");
thread1.start();
– Ist die Sperre beim Eintritt in einen
Monitor gesetzt, muss der aktuelle
Prozeß warten, bis die Sperre
freigegeben wird
public static void main(String[] args) {
p.setName("Peter","Barth");
Thread thread2 = new SyncedThreads();
• Verlassen zurückgesetzt
public class NameSync {
this.p = p;
Thread thread1 = new SyncedThreads();
• Betreten des Bereichts gesetzt
}
public T2(Person p) {
static int counter = 0;
public static void main(String[] args) {
– Sperre wird beim
}
class T2 extends Thread{
public class SyncedThreads extends Thread {
10
10
10
20
20
20
10
10
10
20
20
20
10
10
10
20
20
10
10
10
10
20
20
10
10
10
20
20
10
10
10
20
20
10
10
10
20
20
10
10
10
20
20
10
10
10
20
20
10
10
20 20 20 20 20 20 20 20 20 20
20
20
10
10
10
20
20
20
10
10
10
20
20
20
10
10
10
20
20
20
10
10
10
20
20
20
10
10
10
20
20
20
10
10
10
20
20
20
10
10
10
20
20
20
10
10
10
20
20
20
10
10
10
20
20
20
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
– Darstellung der Animation darf die Interaktivität eines Programms nicht
beeinflussen
– Einzelbilder müssen mit Hilfe von „Double-Buffering“ oder ähnlichen
Techniken gezeichnet werden
Mit synchronized
10
10
10
20
20
20
• Sollen zu viele Bilder gezeichnet werden, können Bildteile „verloren“ gehen
• Naive Verwendung der paint/repaint-Methoden von Java führt zu starkem
Flackern
15
18.06.2009
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
16
Prog. 2
9
•
Prog. 2
Animation in Java
9
Einfach Animation (ohne eigenen Thread)
import java.awt.*;
Eine Animation kann in Java dadurch realisiert werden, dass in einer
Schleife die Methode repaint wiederholt aufgerufen wird
public void startAnimation() {
import java.awt.event.*;
while (true) {
public class SimpleAnim extends Frame {
}
repaint();
– Aufruf von repaint führt zum internen Aufruf der paint-Methode
int count = 0;
}
– paint erzeugt dann das jeweils aktuelle Einzelbild
public static void main(String[] args) {
public void paint(Graphics g) {
SimpleAnim window = new SimpleAnim();
•
Die Methode paint muss wissen, welches Bild bei welchem Aufruf
erzeugt werden soll
count = (count + 10) % getWidth();
window.setBounds(100, 100, 400, 400);
g.fillRect(count, 175, 50, 50);
window.setVisible(true);
try { // 25 frames per second (fps)
window.startAnimation();
– Meist wird hierzu ein Schleifenzähler verwendet, der das aktuelle Bild
bezeichnet
Thread.sleep(40);
}
} catch (InterruptedException e) {}
}
public SimpleAnim() {
– Nach der Ausführung von paint wartet der Aufrufer eine gewisse
Zeitspanne
super("Simple animation");
}
setBackground(Color.BLUE);
addWindowListener(new WindowAdapter()
– Anschließend wird der Schleifenzähler erhöht und erneut paint
aufgerufen
{
public void
windowClosing(WindowEvent e) {
– Das ganze wird solange wiederholt, bis die Animation beendet ist
System.exit(0);
}
});
}
18.06.2009
Prog. 2
9
•
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
17
Verwendung von Threads
9
Damit Programme, die Animationen enthalten, durch diese nicht
komplett lahm gelegt werden, sollten
Haupt-Thread eines Animations-Programms hat dann genug Zeit, um
– die Bildschirmausgabe durchzuführen
– weitere Events zu bearbeiten
Zur Verwendung mehrerer Threads muß die Fensterklasse
– das Interface Runnable implementieren
• Die Methode run() überschreiben
– eine Instanzvariable vom Typ Thread anlegen
18.06.2009
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
18
Einfach Animation (in eigenem Thread)
import java.awt.*;
import java.awt.event.*;
public void startAnimation() {
public class AnimWThread
extends Frame
implements Runnable {
int x = 100, y = 10;
int dx = 10, dy = 10;
public static void main(String[] args) {
AnimWThread window = new
AnimWThread();
window.setBounds(100, 100, 400, 400);
window.setVisible(true);
window.startAnimation();
}
}
Thread thread = new Thread(this);
thread.start();
– Zeitverzögerungen in die repaint-Schleifen verlegt werden
•
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
Prog. 2
– alle repaint-Schleifen in eigenen Threads laufen
•
18.06.2009
19
public void run() {
while (true) {
repaint();
try { // 25 fps
Thread.sleep(40);
} catch (InterruptedException e) {}
}
}
public void paint(Graphics g) {
public AnimWThread() {
x +=dx;
super("Simple animation with thread");
if(x>getWidth()-50 || x<0) dx = -dx;
setBackground(Color.YELLOW);
y +=dy;
addWindowListener(new WindowAdapter()
{
if(y>getHeight()-50 || y<0) dy = -dy;
public void
g.fillRect(x, y, 50, 50);
windowClosing(WindowEvent e) {
}
System.exit(0);
}
}
});
}
18.06.2009
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
20
Prog. 2
9
•
•
Reduzierung des Bildschirmflackerns
1. Bildschirm nicht löschen
import java.awt.*;
import java.awt.event.*;
–
Es erscheint somit kurz ein vollständig leerer Hintergrund
–
Dies führt zu mehr oder weniger starkem „Flackern“ der Animation
public class AnimWThread
extends Frame
implements Runnable {
int x = 100, y = 10;
int dx = 10, dy = 10;
public static void main(String[] args) {
AnimWThread window = new
AnimWThread();
window.setBounds(100, 100, 400, 400);
window.setVisible(true);
window.startAnimation();
}
Bildschirmflackern kann unterschiedlich unterdrückt werden
–
Aufruf von repaint ruft zunächst die Methode update der Klasse Component
public void update(Graphics g) {
Ersetzen durch
g.setColor(getBackground());
g.fillRect(0,0,width,height);
g.setColor(getForeground());
paint(g);
public void update(Graphics g) {
paint(g);
}
}
2. Nur den wirklich benötigen Bildschirmteil löschen und neu zeichnen
3. Double-Buffering (im Hintergrund zeichnen, fertige Zeichnung anzeigen)
18.06.2009
9
9
Vor jedem Aufruf von paint wird zunächst der gesamte Inhalt des
Fensters gelöscht
1. Bildschirm nicht löschen (nur bei nicht bewegten Animationen möglich)
Prog. 2
Prog. 2
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
21
public void startAnimation() {
Thread thread = new Thread(this);
thread.start();
}
public void run() {
while (true) {
repaint();
try { // 25 fps
Thread.sleep(40);
} catch (InterruptedException e) {}
}
}
public void paint(Graphics g) {
x +=dx;
public AnimWThread() {
if(x>getWidth()-50 || x<0) dx = -dx;
super("Simple animation with thread “+
y +=dy;
“(without clearing the frame)“);
if(y>getHeight()-50 || y<0) dy = -dy;
setBackground(Color.YELLOW);
g.fillRect(x, y, 50, 50);
addWindowListener(new WindowAdapter()
}
{
public void
public void update(Graphics g) {
windowClosing(WindowEvent e) {
paint(g);
System.exit(0);
}
}
}
18.06.2009});
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
22
}
Prog. 2
1. Bildschirm nicht löschen
9
•
2. Nur den benötigten Bereich löschen
Bei bewegten Animationen kann es sinnvoll sein, nur die Teile des
Bildschirms zu löschen, die
– im aktuellen Animationsschritt leer sind
– im vorangegangenen Schritt Grafikelemente enthielten
•
Hierzu wird wiederum das automatische Löschen des Bildschirms
durch Überlagern der Methode update verhindert
•
In jedem Animationsschritt müssen alle benötigten Informationen über
den vorangegangenen Schritt vorhanden sein
– Die Applikation muss sich dann selbst um das Löschen der relevanten
Bildbereiche kümmern
18.06.2009
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
23
18.06.2009
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
24
Prog. 2
9
Prog. 2
2. Nur den benötigten Bereich löschen
public void startAnimation() {
Thread thread = new Thread(this);
thread.start();
}
import java.awt.*;
import java.awt.event.*;
public class AnimWThread
extends Frame
implements Runnable {
int x = 100, y = 10;
int dx = 10, dy = 10;
public static void main(String[] args) {
AnimWThread window = new AnimWThread();
window.setBounds(100, 100, 400, 400);
window.setVisible(true);
window.startAnimation();
}
public AnimWThread() {
super("Simple animation with thread “+
“(clear only part of the frame)“);
setBackground(Color.YELLOW);
addWindowListener(new WindowAdapter() {
public void
windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
18.06.2009
Prog. 2
9
9
•
Double-Buffering ist ein universelles Mittel gegen Bildschirmflackern
– Bei jedem Animationsschritt werden
zunächst alle Bildschirmausgaben in
einen Buffer (Offscreen-Image)
geschrieben
public void run() {
while (true) {
repaint();
try { // 25 fps
Thread.sleep(40);
} catch (InterruptedException e) {}
}
}
– Sind alle Ausgaben abgeschlossen,
wir das Offscreen-Image auf die
Fensteroberfläche kopiert
public void paint(Graphics g) {
g.setColor(getBackground());
g.fillRect(x, y, 50, 50);
x +=dx;
if(x>getWidth()-50 || x<0) dx = -dx;
y +=dy;
if(y>getHeight()-50 || y<0) dy = -dy;
g.setColor(Color.BLACK);
g.fillRect(x, y, 50, 50);
}
•
}
Double-Buffering läßt sich in Java komplett kapseln
•
Hierzu leitet man von der Klasse Frame eine neue Klasse
DoubleBufferingFrame ab
Graphics
Offscreen-Image
Bildschirm
2. Kopieren
– Alle Bildschirmausgaben erfolgen auf den Offscreen-Grafikkontext
– Sind alle Ausgabeoperationen abgeschlossen, wird das Offscreen-Image
mittels drawImage in das Ausgabefenster kopiert
25
18.06.2009
Prog. 2
9
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
26
Eine Klasse DoubleBufferFrame
public class DoubleBufferFrame extends Frame {
public void update(Graphics g) {
private Image dbImage;
// Initialising double buffer
private Graphics dbGraphics;
if (dbImage == null || resized) {
private boolean resized;
resized = false;
dbImage = createImage(
public DoubleBufferFrame() {
this.getSize().width,
addCL();
• dbImage enthält das Offscreen-Image
this.getSize().height);
}
• dbGraphics enthält den Offscreen-Grafikkontext
– Zusätzlich muss die Methode update geeignet überschrieben werden
dbGraphics = dbImage.getGraphics();
}
public DoubleBufferFrame(String s) {
// Clear background
super(s);
• In update wird paint mit dbGraphics als Argument aufgerufen
dbGraphics.setColor(getBackground());
addCL();
– paint sendet dann alle Grafikbefehle auf das Offscreen-Image
dbGraphics.fillRect(0, 0,
}
• Zum Schluß wird mittels g.drawImage(dbImage,0,0,this) das OffscreenImage auf dem Bildschirm angezeigt
Auf Änderung der Fenstergröße reagieren
this.getSize().width,
void addCL() {
this.getSize().height);
addComponentListener(
•
Bildschirm
– Mittels getGraphics erhält man einen Grafikkontext zu dem Image
– Die neue Klasse enthält zwei private Membervariable
•
Offscreen-Image
– Ein Fensterobjekt beschafft sich durch Aufruf der Methode createImage
ein Offscreen-Image und speichert es in einer Instanzvariablen
Erweitern der Klasse Frame
•
1. Zeichnen
Prinzipelle Funktionsweise des Double-Bufferings in Java
public void update(Graphics g) {
paint(g);
}
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
3. Double-Buffering
Alle Klassen, die von DoubleBufferingFrame abgeleitet sind,
unterstützen nun das Double-Buffering automatisch
// Paint foreground
new ComponentAdapter() {
dbGraphics.setColor(getForeground());
public void
paint(dbGraphics);
componentResized(ComponentEvent e)
// Show offscreen
{
Damit können schon bestehende Programme nachträglich flackerfrei
gemacht werden, ohne dass eine einzige Zeile der eigentlichen
Ausgaberoutinen geändert werden muss
g.drawImage(dbImage, 0, 0, this);
resized = true;
}
}
});
}
}
18.06.2009
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
27
18.06.2009
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
28
Prog. 2
9
Prog. 2
Animation mit Double-Buffering (Beispiel)
import java.awt.*;
import java.awt.event.*;
9
Double-Buffering Beispiel
public void run() {
while (true) {
repaint();
public class DoubleBufferExample
extends DoubleBufferFrame
implements Runnable {
int xB = 100, yB = 100, xS = 150, yS = 150;
int dx = 10, dy = 10, angle = 0;
double rad;
try { // 25 fps
Thread.sleep(40);
} catch (InterruptedException e) {}
angle = (angle + 10) % 360;
rad = angle*Math.PI/180;
public static void main(String[] args) {
DBExample window = new DBExample();
window.setBounds(100, 100, 400, 400);
window.setVisible(true);
window.startAnimation();
}
xB += dx;
if (xB>getWidth()-70 || xB<0) dx = -dx;
yB += dy;
if (yB>getHeight()-70 || yB<0) dy = -dy;
xS = xB + 15 + (int)(35*Math.sin(rad));
yS = yB + 15 + (int)(35*Math.cos(rad));
public DoubleBufferExample() {
super("Double-Buffering example");
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e)
{
System.exit(0);
}});
}
public void paint(Graphics g) {
public void startAnimation() {
Thread thread = new Thread(this);
thread.start();
}
}
18.06.2009
}
}
g.setColor(Color.BLUE);
g.fillOval(xB, yB, 50, 50);
g.setColor(Color.GREEN);
g.fillOval(xS, yS, 20, 20);
}
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
29
18.06.2009
FH-Wiesbaden --- Medieninformatik --- SS 2009 --- Prof. Dr. Ulrich Schwanecke
30
Herunterladen