2017-09-18 1 views
1

Ich habe einen kritischen Prozess, den ich sicherstellen muss zu jeder Zeit kann nicht zwei äquivalente MyObject verarbeitet werden (kann verschiedene Instanzen sein, aber logisch gleich). Der folgende Code demonstriert die Idee:JAVA Synchronisierung mit zufälliger Zeichenfolge

public class MyClass { 
    public static ConcurrentMap<MyObject, String> concurrentMap = new ConcurrentHashMap<>(); 
    public void process(MyObject myObject) { 
     String id = UUID.randomUUID().toString(); 
     String existingId = concurrentMap.putIfAbsent(myObject, id); 
     synchronized (id) { 
      if (existingId == null) { // no others, start working right away 
       // do work 
      } else { // an equivalent myObject is under processing, wait on it 
       synchronized (existingId) { 
        // finally can start doing work 
       } 
      } 
     } 
    } 
} 

Der obige Code funktioniert mit Hilfe von synchronized auf einer zufälligen Zeichenfolge. Aber die Probleme mit diesem Code sind

  1. Jedes Mal, es einen neuen Zufall-ID erzeugt wird, aber nicht verwendet, wenn eine bestehende ID zu einem äquivalenten MyObject in Verbindung gebracht wurde. Der einzige Zweck einer solchen ID besteht darin, als eine einzigartige Sperre zu agieren, die von dem anderen Thread entdeckt werden soll. Denken Sie daran, dass dies durch ein tatsächliches Sperrobjekt ersetzt werden kann?

  2. Es gibt keine Möglichkeit in diesem Code zu wissen, wann MyObject aus der concurrentMap entfernt werden sollte, obwohl dies das Ergebnis nicht beeinflusst. Wenn die concurrentMap wächst, ist das möglicherweise nicht gut. Denken Sie daran, dass hier so etwas wie eine Ladentheke verwendet werden kann?

Danke

+0

Es tut. Die ID wird in der Map gespeichert und von einem anderen Thread extrahiert (wird zu existingId) – user1589188

+0

OK, ich sehe deine Punkte. Ich werde den Kommentar niederschreiben. – markspace

Antwort

2

Ich glaube nicht verstehen den Anwendungsfall für diese Idee, die ich, wirklich und das ist eine große rote Fahne. Aber es scheint mir, dass all dieser Code unnötig ist. Wenn die einzige Idee hier ist, eine eindeutige Sperre für myObject zu erhalten, dann haben Sie bereits das: es ist myObject.

public class MyClass { 

    public void process(MyObject myObject) { 
     synchronized (myObject) { 
      // finally can start doing work 
     } 
    } 
} 

Der Rest des Codes ist nur Eigengewicht.

Allerdings ist dies immer noch angespannt. Da Sie auf eine externe Prozedur angewiesen sind, um Ihr Objekt zu synchronisieren, kann jedes andere Codebit mit einem Verweis auf myObject tun, was immer Sie möchten, und Sie haben keine Kontrolle darüber. Es ist eine wirklich schwache Form der Synchronisation. Es kann funktionieren, wenn jeder in der Codebasis die Notwendigkeit versteht, auf ihrer MyObject zu synchronisieren, aber das könnte in der Praxis schwer zu erreichen sein.

+0

Wie ich in der Eröffnung sagte, kann es verschiedene Instanzen von MyObject-Objekten geben, die verarbeitet werden. Kann nicht auf myObject synchronisiert werden. – user1589188

+0

Sie sagen, Sie wollen eine globale Sperre für alle Instanzen? Das ist nicht der Code, den Sie gepostet haben. – markspace

+0

Nein, ich möchte eine Sperre pro logisch gleiche MyObjects. Also, wenn ich 'neues MyObject (" a ")' und 'neues MyObject (" b ")' durch die Karte habe, sollten sie unterschiedliche ID haben und sich nicht gegenseitig verriegeln. Aber wenn bereits ein 'MyObject (" a ")" verarbeitet wird, dann sollte ein anderes 'neues MyObject (" a ")' die gleiche ID über die Map bekommen, also sperren und warten bis zum ersten 'MyObject (" a ") 'zu vervollständigen. P.S. Ich überschreibe 'equals' und' hashCode' in 'MyObject', um true zurückzugeben, wenn beide den gleichen Wert haben. – user1589188

0

Ich denke, this Bibliothek ist, was Sie suchen. Insbesondere StripedKeyLockManager und CountingLock Klassen, die Ihre Fragen beantworten. Sie können entweder die Bibliothek in Ihrem Projekt verwenden oder den Quellcode an Ihre Bedürfnisse anpassen. Guava bietet auch ähnliche Funktionalität über Stripped Klasse.