Anzeige:
Ergebnis 1 bis 6 von 6

Thema: Klasse vor parallelem Zugriff absichern

  1. #1
    Registrierter Benutzer
    Registriert seit
    08.07.2002
    Beiträge
    377

    Klasse vor parallelem Zugriff absichern

    Ich habe hier mal ne Klasse, zu der ich euren Rat brauche:

    Code:
    import java.io.Serializable;
    import java.util.LinkedList;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.locks.ReentrantLock;
    
    public final class MsM implements Serializable {
    
    	private static final long serialVersionUID = -7772563564882078067L;
    	private static final MsM manager = new MsM();
    	private final ReentrantLock messagesLock = new ReentrantLock();
    	private final ReentrantLock filtersLock = new ReentrantLock();
    	private LinkedBlockingQueue<Object> messages;
    	private LinkedList<FilterPlugin> filters;
    
    	private MsM() {
    		this.messages = new LinkedBlockingQueue<Object>();
    		this.filters = new LinkedList<FilterPlugin>();
    	}
    	
    	public static MsM getInstance() {
    		return MsM.manager;
    	}
    	
    	public void addFilter(FilterPlugin plugin) {
    		final ReentrantLock addLock = this.filtersLock;
    		addLock.lock();
    		try {
    			this.filters.add(plugin);
    		} finally {
    			addLock.unlock();
    		}
    	}
    	
    	public void clearFilters() {
    		final ReentrantLock clearLock = this.filtersLock;
    		clearLock.lock();
    		try {
    			this.filters.clear();
    		} finally {
    			clearLock.unlock();
    		}
    	}
    	
    	public void addMessage(Object message) throws MoeException {
    		final ReentrantLock putLock = this.messagesLock;
    		final ReentrantLock iterLock = this.filtersLock;
    		try {
    			putLock.lockInterruptibly();
    			iterLock.lockInterruptibly();
    			
    			for (FilterPlugin plugin : this.filters) {
    				message = plugin.filter(message);
    				if (message == null) 
    					break;
    			}
    			if (message != null)
    				this.messages.put(message);
    		} catch (InterruptedException e) {
    			throw new MoeException("Queue interrupted in put() method!");
    		} finally {
    			iterLock.unlock();
    			putLock.unlock();
    		}
    	}
    	
    	public synchronized boolean hasMessages() {
    		return this.messages.size() > 0;
    	}
    	
    	public Object getMessage() {
    		final ReentrantLock takeLock = this.messagesLock;
    		takeLock.lock();
    		Object o = null;
    		try {
    			o = this.messages.poll();
    		} finally {
    			takeLock.unlock();
    		}
    		return o;
    	}
    }
    Die Instanz dieser Klasse wird von mehreren Threads genutzt.

    1. Thread fuegt dauernd neue Nachrichten hinzu
    2. Dieser Thread holt die Nachrichten aus der Klasse wieder raus
    und
    3. Der Thread fuegt Filter hinzu, diese Filter werden beim Hinzufuegen der Nachrichten benutzt um bestimmte Daten zu filtern.

    Nun habe ich die Klasse mit 2 ReentrantLock abgesichert.

    Zugegeben, ich habe nicht wirklich viel Erfahrung mit mehr als einem Thread, aber koennte das so passen?

    Hoffe jemand macht sich die Muehe darueber nachzudenken.

    mfg
    Amilo D - 2,8 Ghz - ATI Radeon 9000
    Debian GNU/Linux 3.1 (Sarge)

  2. #2
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Wenn du nicht spezielle Laufzeitanforderungen hast, die getrenntes Locking benötigen, würde ich einfach die Accessor Methoden der Klasse selbst synchronized machen und Java die Zugriffssteuerung überlassen.

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  3. #3
    Registrierter Benutzer
    Registriert seit
    02.12.2002
    Ort
    Darmstadt
    Beiträge
    615
    Das wuerde in soweit nicht funktionieren, als das zur Zeit nur ein Prozess generell auf bspw. this.filters zugreifen darf (gleiches Lock in den drei Methoden). Wuerde man nur die Methoden selbst synchronized deklarieren, heisst das nur, das die Methode nur von einem Prozess aufgerufen werden kann, eine andere Methode ist dadurch aber nicht gesperrt (bspw. koennte dann Prozess B waehrend Prozess A auf addFilter() zugreift durchaus die Methode clearFilter() aufrufen, was in dieser Konstellation jetzt nicht moeglich ist).

    Je nachdem ob noch weitere Methoden hinzugefuegt werden zu der Klasse musst du aber auf Deadlocks aufpassen. Zudem ist vielleicht die ReentrantReadWriteLock eine Ueberlegung Wert um hasMessages() zu sichern. (Ich bin grad nicht ganz sicher: Falls poll() das Objekt aus messages entfernt wuerde ich das empfehlen)
    Seine Rätselhaftigkeit wird nur durch seine Macht übertroffen!

  4. #4
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Zitat Zitat von mehlvogel Beitrag anzeigen
    Das wuerde in soweit nicht funktionieren, als das zur Zeit nur ein Prozess generell auf bspw. this.filters zugreifen darf (gleiches Lock in den drei Methoden). Wuerde man nur die Methoden selbst synchronized deklarieren, heisst das nur, das die Methode nur von einem Prozess aufgerufen werden kann, eine andere Methode ist dadurch aber nicht gesperrt (bspw. koennte dann Prozess B waehrend Prozess A auf addFilter() zugreift durchaus die Methode clearFilter() aufrufen, was in dieser Konstellation jetzt nicht moeglich ist).
    Bist du dir sicher?
    Ich dachte immer, wenn die Methoden synchronized sind, dann gilt immer der Monitor des Objekts, also kann immer nur eine Methode gleichzeitig ablaufen.

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  5. #5
    Registrierter Benutzer
    Registriert seit
    02.12.2002
    Ort
    Darmstadt
    Beiträge
    615
    Nein, du hast Recht. Ich hab mich geirrt. Die Methode kann zwar mehrfach aufgerufen werden, allerdings nur für zwei verschiedene Objekte (siehe [2]). Sprich beim einem Objekt wird immer nur eine der sychronized Methoden aufgerufen. Ein schöner Artikel zum Thema synchronized vs ReentrantLock ist [1]. Dort kommt man zum Ergebnis: "[..]make the decision on the basis of whether you need the power of ReentrantLock. In the vast majority of cases, you will not -- synchronization works just fine[..]"

    Memo an mich: Auch auf der Arbeit vorher in die Artikel sehen

    [1] http://www.ibm.com/developerworks/ja...ry/j-jtp10264/
    [2] http://www.ibm.com/developerworks/ja...axis/pr46.html
    Seine Rätselhaftigkeit wird nur durch seine Macht übertroffen!

  6. #6
    Registrierter Benutzer
    Registriert seit
    17.09.2001
    Beiträge
    1.182
    Ich würde in jedem Fall synchronized den Lock-Klassen in solchen Fällen vorziehen wenn nur geringe contention zu erwarten ist - die JVM kann in diesem Fall viel wegoptimieren.
    Geändert von Lin728 (21-08-2017 um 16:09 Uhr)

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •