73. Threading Anomalien (Beispiele)
Attention
Lokale Variablen in der run() Methode besitzt jeder Thread für sich selbst. Greifen die Threads zeitgleich auf eine globale Klassenvariable zu, so verändern sie diese parallel.
Example 1
package programme;
public class CrazyThreads1 implements Runnable
{
boolean alive;
long i;
@Override
public void run()
{
System.out.println("Thread starts...");
i = 0;
alive = true;
while (true) //Langfassung f�r while (alive = true) { i++; }
{
if (alive)
{
i++;
}
else
{
break;
}
}
System.out.println("Thread ends...");
}
public static void main(String[] args)
{
CrazyThreads1 c = new CrazyThreads1(); //ein zweiter Thread wird erzeugt (zus�tzlich zu main())
new Thread(c).start(); //run() Methode der Instanz-Methode wird in einem neuen Thread ausgef�hrt
// Die Methode pr�ft den aktuellen Wert von i im zweiten Thread. �bersteigt dies 1 Milliarde, so wird der Thread beendet
while (Thread.activeCount() > 1) //mindestens zwei gerade aktive Threads
{
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
long iNow = c.i;
System.out.println(iNow);
if (iNow >= LIMIT)
{
c.alive = false;
System.out.println("THREAD STOPPED! (alive = " + c.alive + ")");
}
}
System.out.println("Program exits...");
/*Das Programm endet nie (die if-Schleife wird nie verlassen)
* Auch wenn alive = false ist und i bereits 1 Milliarde �berschritten hat l�uft das Programm ewig weiter
*/
}
private static final long LIMIT = 1000000000L;
}
Example 2
package programme;
public class CrazyThreads2 implements Runnable
{
int x;
@Override
public void run() {
int i;
for ( i = 0; i < 2000; i++){
x++;
}
System.out.println(Thread.currentThread().getName() + " has finished after " + i + " loops");
}
public static void main(String[] args){
CrazyThreads2 c = new CrazyThreads2();
new Thread(c).start(); //Thread wird ohne Zuweisung an eine Variable gestartet
new Thread(c).start(); //Thread wird abermals gestartet
//Achtung: Beide Threads durchlaufen zeitgleich die run() Methode, d.h. erh�hen die Instanzvariable x
//Die lokale Variable i teilen sich die beiden Threads nicht, sondern jeder besitzt ein eigenes lokales i
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("x is: " + c.x);
/*Ausgabe ist bei jeder Ausf�hrung unterschiedlich:
Thread-1 has finished after 2000 loops
Thread-0 has finished after 2000 loops
x is: 3291
- x ist h�ufig nicht die Summe aus Thread 1 und 2 (sollte stets 4000 sein)
*/
}
}
Example 3
package programme;
public class CrazyThreads3 implements Runnable
{
int x;
@Override
public void run() {
int loops = 0;
//x wird erh�ht, bis 10000 erreicht ist (egal welcher Thread x wie oft erh�ht)
while (true) {
if (x < 10000) {
x++;
loops++;
} else {
break;
}
}
System.out.println(Thread.currentThread().getName() + " has finished after " + loops + " loops");
}
public static void main(String[] args)
{
CrazyThreads3 a = new CrazyThreads3();
new Thread(a).start();
new Thread(a).start();
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("x is: " + a.x);
/*Ausgabe ist bei jeder Ausf�hrung unterschiedlich, da man nicht beeinflussen kann, welcher Thread wann startet (Scheduling):
Thread-1 has finished after 6305 loops
Thread-0 has finished after 8700 loops
x is: 10001
- x(thread1) + x(thread2) ist stets �ber 10000 (sollte in der Summe genau 10000 sein)
- x ist manchmal auch mehr als 10000 (sollte auch stets 10000 sein)
*/
}
}