Announcement

Collapse
No announcement yet.

Frage zur Synchronisierung mit synchronised-Block

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Frage zur Synchronisierung mit synchronised-Block

    Hallo!

    Mir ist nicht ganz klar, was ich bei einem synchronised-Block als Parameter angeben kann.

    Da muss ja das Objekt oder die Klasse hin, deren intrisic lock ich haben möchte. Aber ich verstehe nicht genau, welche Klassen und Objekte das sein können. Immer nur die Klasse oder das Objekt, deren Methode ich aufrufe? D. h. ich kann "this" (gesamte Instanz der Klasse blablabla) , "blabla.class" oder ein Instanzfeld der Klase blablabla als lock nehmen? Und bei "this" habe ich den Nachteil, dass ich den lock für alle synchronised-Blöcke gleichzeitig erwerbe. Oder wieso macht mann z. B. Folgendes?

    Code:
    public class MsLunch {
        private long c1 = 0;
        private long c2 = 0;
        private Object lock1 = new Object();
        private Object lock2 = new Object();
    
        public void inc1() {
            synchronized(lock1) {
                c1++;
            }
        }
    
        public void inc2() {
            synchronized(lock2) {
                c2++;
            }
        }
    }
    D. h. dadurch sorge ich dafür, dass mein Objekt mehrere locks hat und nicht nur einen?

  • #2
    http://docs.oracle.com/javase/tutori.../syncmeth.html

    If count is an instance of SynchronizedCounter, then making these methods synchronized has two effects:
    • First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
    • Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.
    Christian

    Comment


    • #3
      Komme die Tage drauf zurück, ich schreib mal ein kleines Beispiel, um meine Frage zu illustrieren.

      Comment


      • #4
        Code:
        public class MeineThreadTests implements Runnable {
        
        	private int counter;
        	private Date datum = new Date();
        
        	public void upCounter1() {
        		synchronized (datum) {
        			for (int i = 0; i < 5; i++) {
        				counter++;
        				System.out.println("1 " + counter);
        			}
        		}
        
        	}
        
        	public void upCounter2() {
        		synchronized (datum) {
        			for (int i = 0; i < 5; i++) {
        				counter++;
        				System.out.println("2 " + counter);
        			}
        		}
        	}
        
        	public void upCounter3() {
        		synchronized (datum) {
        			for (int i = 0; i < 5; i++) {
        				counter++;
        				System.out.println("3 " + counter);
        			}
        		}
        	}
        
        	@Override
        	public void run() {
        		upCounter1();
        		upCounter2();
        		upCounter3();
        	}
        
        	public static void main(String[] args) {
        		MeineThreadTests mtt = new MeineThreadTests();
        		Thread t1 = new Thread(mtt);
        
        		Thread t2 = new Thread(mtt);
        
        		Thread t3 = new Thread(mtt);
        
        		t1.start();
        		t2.start();
        		t3.start();
        	}
        
        }
        So, meine Beispielklasse, etwas spät.

        Meine Schlussfolgerungen aus mehreren Durchläufen und Kombinationen:
        - wenn mehrere Threads Methoden aufrufen, die kritisch sind, dann klappt
        Code:
        synchronised (this)
        oder das synchronisieren der Instanzmethoden nur dann, wenn ich allen Threads dieselbe Instanz übergebe. Falls ich den Threads andere Instanzen übergebe, muss ich entweder synchronised(getClass()) nehme oder static synchronised Methoden nehmen, weil ja sonst jede Instanz einen lock hat und die Threads ungeniert die Methoden aufrufen können

        - statt
        Code:
        (this)
        kann ich auch irgendeine Andere Instanz nehmen, also z. B. [CODE}synchronised (new Date());[/CODE] oder wie oben Date als privates Feld

        - Ich kann aber statt
        Code:
        synchronised (getClass())
        nicht sowas machen wie [CODE]synchronised (Date.class)[CODE]

        - wenn ich Methoden habe, die ich unabhängig voneinander synchronisieren will (weil der lock ja immer für alle synchronisierten Methoden erworben wird), dann kann ich auch mehrere private Felder anlegen (z. B. private Object lock = new Object()) und das dann im synchronised-Block benutzen

        - wenn ich den Klassen-lock benutze, dann wird jeder der Methoden als "separate Methode" gesehen, also die Counter laufen nur bis 15. Wenn ich den Instanz-Lock nehme, dann läuft der Counter bis 45

        - volatile bringt nur dann was, wenn die Operation wirklich atomar ist (counter++ besteht ja aus zwei Schritten)

        So, ist das alles richtig beobachtet?

        Und wieso gibt es bei
        Code:
        synchronised (this)
        Probleme wegen der Sichtbarkeit? Wenn jemand meine Klasse, in der ich mit
        Code:
        synchronised (this)
        synchronisiere, instanziiert, und dann diese Instanz meiner Klasse als Instanz für einen synchronised-Block bei sich benutzt, klaut er mir dann den lock für den lock von meiner Klasse?

        Comment

        Working...
        X