komplexe synchronized bedingungen

Stahlkocher

Mitglied
Hallo zusammen.

Ich habe mehrere Codeblöcke, nennen wir sie BlockA, BlockB und BlockC.
In alle dürfen so viele Threads rein wie wollen.

Nun hab ich einen Weiteren BlockX. Wenn hier ein Tread reinkommt, dann darf in keinem der anderen Blöcke ein Thread sein.

Ich könnte jetzt natürlich die drei Blöcke A, B und C mit drei verschiedenen Mutex (was ist eigentlich der plural von Mutex?) schützen. Und BlockX verwendet alle über ein dreifach verschafteltes synchronized. Aber dann kann in den Blöcken jeweils nur ein Thread, was eine zimliche Spaßbremse wäre...

Was ich bräuchte ist sowas wie ein "synchronized_read_only". Gibts ihrgendetwas in die Richtung? Wie könnte ich das umsetzten?

lg
Stahlkocher

Java:
public void functionA() {
  doSomething();
  synchronized(MutexA, read_only) {
    doSomething();
  }
  doSomething();
}

public void functionB() {
  doSomething();
  synchronized(MutexB, read_only) {
    doSomething();
  }
  doSomething();
}

public void functionC() {
  doSomething();
  synchronized(MutexC, read_only) {
    doSomething();
  }
  doSomething();
}

public void functionX() {
  doSomething();
  synchronized(MutexA) {
    synchronized(MutexB) {
      synchronized(MutexC) {
        doSomethingDirty();
      }
    }
  }
  doSomething();
}
 
Vergiss synchronized ganz schnell wieder! Das Concurrency-Framework sollte dir das bieten, was du brauchst.
Schau dir ReentrantLock bzw. ReentrantReadWriteLock an.
 
Perfekt.

ReentrantReadWriteLock scheint genau das zu sein was ich brauche. Wusste garnicht, dass es in der java API ein synchronized-extended-framework gibt. Coole sache.

lg
Stahlkocher
 
Ich hab spaßeshalber mal ein kleines Beispiel programmiert:

Java:
import java.util.Random;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ABCLock {

    static final Random rand = new Random();

    ReentrantReadWriteLock lockA = new ReentrantReadWriteLock();
    ReentrantReadWriteLock lockB = new ReentrantReadWriteLock();
    ReentrantReadWriteLock lockC = new ReentrantReadWriteLock();

    public void methodA() {
        try {
            this.lockA.readLock().lock();
            System.out.println("A " + Thread.currentThread().getName());
        }
        finally {
            this.lockA.readLock().unlock();
        }
    }

    public void methodB() {
        try {
            this.lockB.readLock().lock();
            System.out.println("B " + Thread.currentThread().getName());
        }
        finally {
            this.lockB.readLock().unlock();
        }
    }

    public void methodC() {
        try {
            this.lockC.readLock().lock();
            System.out.println("C " + Thread.currentThread().getName());
        }
        finally {
            this.lockC.readLock().unlock();
        }
    }

    public void methodX() {
        try {
            this.lockA.writeLock().lock();
            this.lockB.writeLock().lock();
            this.lockC.writeLock().lock();

            for (int i = 0; i < 10; i++) {
                System.out.println("X." + i);
                sleep(rand.nextInt(300));
            }
        }
        finally {
            this.lockA.writeLock().unlock();
            this.lockB.writeLock().unlock();
            this.lockC.writeLock().unlock();
        }
    }

    public void sleep(int t) {
        try {
            Thread.sleep(t);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public Runnable job() {
        return new Runnable() {
            public void run() {
                while (true) {
                    switch (rand.nextInt(3)) {
                        case 0: methodA(); break;
                        case 1: methodB(); break;
                        case 2: methodC(); break;
                    }
                    sleep(rand.nextInt(300));
                }
            }
        };
    }

    public void test() {
        for (int i = 0; i < 10; i++) {
            new Thread(job()).start();
        }

        Thread x = new Thread(new Runnable() {

            public void run() {
                while (true) {
                    methodX();
                    sleep(5000);
                }
            }
        });
        x.start();
    }

    public static void main(String[] args) {
        new ABCLock().test();
    }

}

10 Threads rufen wahllos die Methoden A, B und C auf. Bis Thread X daher kommt und die anderen zum Schweigen bringt.
 
Ich hab spaßeshalber mal ein kleines Beispiel programmiert
Was man Donnerstag nachmittags halt so macht 😀

Danke für das beispiel.
Wenn ich das richtig verstanden hab könnte man das noch vereinfachen. Kann ich nicht alle drei Blöcke/Methoden mit nur einem ReentrantReadWriteLock'er schützen?

Java:
import java.util.Random;
import java.util.concurrent.locks.ReentrantReadWriteLock;
 
public class ABCLock {
 
    static final Random rand = new Random();
 
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
 
    public void methodA() {
        try {
            this.lock.readLock().lock();
            System.out.println("A " + Thread.currentThread().getName());
        }
        finally {
            this.lock.readLock().unlock();
        }
    }
 
    public void methodB() {
        try {
            this.lock.readLock().lock();
            System.out.println("B " + Thread.currentThread().getName());
        }
        finally {
            this.lock.readLock().unlock();
        }
    }
 
    public void methodC() {
        try {
            this.lock.readLock().lock();
            System.out.println("C " + Thread.currentThread().getName());
        }
        finally {
            this.lock.readLock().unlock();
        }
    }
 
    public void methodX() {
        try {
            this.lock.writeLock().lock();
 
            for (int i = 0; i < 10; i++) {
                System.out.println("X." + i);
                sleep(rand.nextInt(300));
            }
        }
        finally {
            this.lock.writeLock().unlock();
        }
    }
 
    public void sleep(int t) {
        try {
            Thread.sleep(t);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
 
    public Runnable job() {
        return new Runnable() {
            public void run() {
                while (true) {
                    switch (rand.nextInt(3)) {
                        case 0: methodA(); break;
                        case 1: methodB(); break;
                        case 2: methodC(); break;
                    }
                    sleep(rand.nextInt(300));
                }
            }
        };
    }
 
    public void test() {
        for (int i = 0; i < 10; i++) {
            new Thread(job()).start();
        }
 
        Thread x = new Thread(new Runnable() {
 
            public void run() {
                while (true) {
                    methodX();
                    sleep(5000);
                }
            }
        });
        x.start();
    }
 
    public static void main(String[] args) {
        new ABCLock().test();
    }
 
}

Der Consolen-output schaut danach aus als würds funktionieren 🙂

lg
Stahlkocher
 

Neue Themen


Zurück
Oben