# Threads und synchronized



## Lorus (7. Nov 2008)

Hallo Zusammen,

anscheint habe ich die ganze Sache noch nicht so recht verstanden.
Ich möchte 3 Threads erstellen, die eine gemeinsame Zählvariable besitzen, die synchronisiert werden soll.

Eine Ausgabe soll dann also ca. so aussehen:



> Thread 1: 1
> Thread 3: 2
> Thread 1: 3
> Thread 2: 4
> ...



Folgenden Code habe ich mir dazu nun gebastelt:


```
class Counter {
    int Counter=0;
        
    public synchronized int getCounterValue() {
        return Counter;
    }
        
    public synchronized void incrementCounter() {
        Counter++;
    }
}

class TextThread extends Thread {
    String text;

    public TextThread(String text) {
        this.text = text;
    }

    public void run() {
    
        Counter count = new Counter();

        while(count.getCounterValue() < 10) {
            count.incrementCounter();  
            try {
                sleep((int)(Math.random()*1000));
            }
            catch(InterruptedException e) { 
            }
            System.out.println(text + ": " + count.getCounterValue()); 
        }
    }
} 

class TextThreadDemo {

    public static void main(String args[]) {
        TextThread t1, t2, t3;
    
        t1= new TextThread("Thread 1");
        t2 = new TextThread("Thread 2");
        t3 = new TextThread("Thread 3");
        t1.start();
        t2.start();
        t3.start();
    }
}
```

Erhalte allerdings ca. folgende Ausgabe:





> Thread 1: 1
> Thread 3: 1
> Thread 2: 1
> Thread 1: 2
> ...



Wieso zählt da nun jeder Thread für sich selbst? der Counter sollte doch eigentlich synchronisiert sein :-/

Für einen Denkanstoß wäre ich sehr dankbar 

Grüße,

Lorus


----------



## Wildcard (7. Nov 2008)

Jeder Thread hat seinen eigenen Counter, die haben nicht das geringste miteinander zu tun.


----------



## Lorus (7. Nov 2008)

Wie kann man es denn dann hinbekommen, das sie einen gemeinsamen Counter benutzen?
Ich dachte für sowas ist das synchronized gemacht.

Hast du irgend einen Denkanstoß für mich, wie ich das realisieren könnte?


Vielen Dank,

Lorus


----------



## musiKk (7. Nov 2008)

Dafür ist synchronized nicht. Wenn du verschiedene Instanzen eines Objekts separat behandelst, gibt es nichts zu synchronisieren. Synchronisiert werden muss dann, wenn mehrere Threads auf das selbe Objekt zugreifen.

Du könntest einen statischen Counter benutzen oder ein einziges Counter-Objekt initialisieren und allen drei Threads (z. B. über den Konstruktor) zuweisen.


----------



## Guest (7. Nov 2008)

musiKk hat gesagt.:
			
		

> Dafür ist synchronized nicht. Wenn du verschiedene Instanzen eines Objekts separat behandelst, gibt es nichts zu synchronisieren. Synchronisiert werden muss dann, wenn mehrere Threads auf das selbe Objekt zugreifen.
> 
> Du könntest einen statischen Counter benutzen oder ein einziges Counter-Objekt initialisieren und allen drei Threads (z. B. über den Konstruktor) zuweisen.



Ok, das habe ich nunmal versucht ... hier der neue Code:


```
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package http;

/**
 *
 * @author clorentz
 */
class Counter {
    int Counter=0;
        
    public synchronized int getCounterValue() {
        return Counter;
    }
        
    public synchronized void incrementCounter() {
        Counter++;
    }
}

class TextThread extends Thread {
    String text;
    Counter count;

    public TextThread(String text, Counter count) {
        this.count = count;
        this.text = text;
    }

    public void run() {
        
        while(count.getCounterValue() < 10) {
            count.incrementCounter();  
            try {
                sleep((int)(Math.random()*1000));
            }
            catch(InterruptedException e) { 
            }
            System.out.println(text + ": " + count.getCounterValue()); 
        }
    }
} 

class TextThreadDemo {

    public static void main(String args[]) {
        TextThread t1, t2, t3;
        Counter count = new Counter();
        t1= new TextThread("Thread 1",count);
        t2 = new TextThread("Thread 2",count);
        t3 = new TextThread("Thread 3",count);
        t1.start();
        t2.start();
        t3.start();
    }
}
```

Nun bekomm ich aber folgendes Ergebnis:



> Thread 3: 3
> Thread 1: 4
> Thread 3: 5
> Thread 2: 6
> ...



Nun greifen sie wohl allerdings zeitgleich auf den Counter zu ... und so soll es ja nicht sein .... jede Ausgabe des Counters-Standes soll ja nur genau einmal erfolgen.


----------



## Ark (7. Nov 2008)

Ein synchronized in der Methodendeklaration bewirkt das gleiche, als würde man den gesamten Rumpf dieser Methode von einem synchronized(this) umschließen. Bei this handelt es sich allerdings für jedes Objekt um ein anderes, weshalb ein synchronized(this) praktisch wirkungslos ist.

Nimm das synchronized doch mal aus den Methodendeklarationen raus und packe dafür die Rümpfe jeweils in einen synchronized(Counter.class)-Block:

```
public int getCounterValue() {
    synchronized(Counter.class){
        return Counter;
    }
}
```
usw. Das, denke ich, sollte dann funktionieren.

Ark


----------



## Landei (8. Nov 2008)

Sollte so gehen wie Ark schreibt. Eine Alternative wäre java.util.concurrent.atomic.AtomicReference, das ist sozusagen ein synchronisierter Wrapper um die Variable.


----------



## Guest (8. Nov 2008)

Hab gerade ein ähnliches Problem, aber das mit 

```
Counter.class
```
 funktioniert auch nicht.  Habs ausprobiert. Es sieht zuerst so aus, als ob
der Counter synchronisiert hochgezählt wird, aber wenn die Threads immer genauso lang 
schlafen, dann kommt bei mir

Thread 3: 3
Thread 1: 3
Thread 2: 3
Thread 1: 6
Thread 2: 6
Thread 3: 6
Thread 2: 9
Thread 3: 9
Thread 1: 9
Thread 2: 10


----------



## tfa (8. Nov 2008)

Landei hat gesagt.:
			
		

> Sollte so gehen wie Ark schreibt.


Nein. Im zweiten Beispiel gibt es doch nur noch eine Counter-Variable. Dann ist es völlig egal, ob hier auf die Variable oder die Klasse synchronisiert wird. Da kommt das selbe raus.

Wenn wirklich das ausgegeben werden soll, was oben gefordert wird, muss das Inkrementieren und Holen des Wertes eine atomare Transaktion sein, z.B.


```
while(count.getCounterValue() < 10) { 
     synchronized (count) {
          count.incrementCounter();
          System.out.println(text + ": " + count.getCounterValue());	
     }
     try { 
          sleep((int)(Math.random()*1000)); 
     } 
     catch(InterruptedException e) { }
}
```


----------

