2016-08-12 3 views
2

Ich habe eine Methode:synchronisierte Methode Zugriff von anderen Objekten JAVA

private synchronized Long generateID (Short company) throws Exception { 
    IDDAO iDDAO = SpringApplicationContext.getBean (IDDAO.class); 
    ID iD = iDDAO.findByNaturalKey (new IDNatKey (company); 

    if (iD != null) { 
     // Check if ID has reached limit, then reset the ID to the first ID 
     if (iD.getLatestIDno().longValue() == iD.getLastIDno().longValue()) { 
      iD.setLatestIDno (iD.getFrstIDno()); 
     } 

     // Get next ID 
     iD.setLatestIDno (iD.getLatestIDno() + 1); 
     // update database with latest id 
     iDDAO.update (iD); 

     return iD.getLatestIDno(); 
    } 
} 

In diesem Code Ich iD.setLatestIDno(iD.getLatestIDno() + 1) den Wert der ID zu aktualisieren. Dies geschieht in einer synchronisierten Weise, so dass es niemals dupliziert wird, wenn von mehreren Threads aus zugegriffen wird.

Meine Frage ist, wenn diese Methode synchronisiert wird verhindert, dass andere Threads darauf zugreifen? Oder können andere Threads von verschiedenen Objekten darauf zugreifen? Soll es also statisch gemacht werden?

Der Code wie folgt verwendet wird

Long check = generateID (123); 

Dank

+0

Kann mir jemand bitte zeigen, wie incrementAndGet() von Atomic verwenden, indem Sie meinen Code Bearbeitung ? – Aiden

Antwort

3

Andere Threads es von einer anderen Instanz zugegriffen werden:

public synchronized Long generateID(Short company) { 
    // do something 
} 

entspricht:

public Long generateID(Short company) { 
    synchronized(this) { 
     // do something 
    } 
} 

Also wenn this verweist auf eine andere Instanz, der Thread wird nicht blockiert.

Wenn Sie Threads über verschiedene Instanzen synchronisieren möchten, müssen Sie eine gemeinsame Sperre bieten:

Object lock = new Object(); 
MyClass c1 = new MyClass(lock); 
MyClass c2 = new MyClass(lock); 
// ... 

// in MyClass: 
private Long generateID(Short company) { 
    synchronized(lock) { 
     // do something 
    } 
} 

Sie können auch eine Verwendung Lock statt synchronized auf einem Objekt verwendet wird. Die Logik bleibt jedoch ähnlich.

Da Sie SpringApplicationContext verwenden, können Sie eine ReentrantLock erstellen und in Ihrem Kontext hinzufügen und es dann auf den gleichen Sie die IDDAO Instanz zugreifen.

+0

Es ist eine private Methode, und es sieht so aus, als würde es nur von 'this' als ursprünglich geschriebene Datei aufgerufen werden und niemals auf andere Objekte zugreifen. –

+0

Gibt es eine Möglichkeit, ganze Methode für alle zu sperren, alle Instanzen ohne gemeinsame Sperre? – Aiden

+0

Ich frage mich, ob das OP ein verkapptes [XY-Problem] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) stellt und sich fragen muss, was das Motiv ist hinter der Frage. –

1

oder einige andere Threads können von verschiedenen Objekten darauf zugreifen?

Natürlich sind sie can, synchronized ist nur für Threads auf bestimmtes Objekt zu synchronisieren. Ich würde es auch nicht statisch machen - der einfachste Weg, um das zu erreichen, was Sie tun möchten, ist die Verwendung der incrementAndGet() Methode aus der AtomicInteger (javadoc) Klasse.

Definition:

public static AtomicInteger counter = new AtomicInteger(0); 
// starting number is 0, but can be changed 

Verbrauch:

int id = counter.incrementAndGet(); // assigns number 1 
int otherId = counter.incrementAndGet(); // assigns 2 

Sie viele Beispiele finden, wenn Sie sie googeln, F. E. this one. Es gibt viele andere Methoden, die AtomicInteger anbietet, ich schlage vor, dass Sie sich das Javadoc ansehen (siehe zweiten Link).

Thruth zu sagen, ich habe nicht bekommen, warum Sie IDs zurücksetzen - aber okay, sagen wir, Sie müssen das tun.Wenn ID durch Grenzwert überschreitet (wir konstant MAXIMUM_ID sagen), gibt es viele Möglichkeiten, wie das zu tun:

  • Verwendung Modulo: counter.incrementAndGet() % MAXIMUM_ID, aber Überlauf passieren kann, so müssen Sie sich darum kümmern;

  • naive Lösung könnte sein, nur den Zähler zurücksetzen:

    id = counter.incrementAndGet(); // too high 
    if(id > MAXIMUM_ID) { 
        counter = new AtomicInteger(0); 
        id = counter.incrementAndGet(); // gets 1 
    } 
    

Welche Überlauf verhindert. Aber dann kann Concurrency Problem passieren - man stelle sich zwei neue Zähler geschaffen, also beide erhält die Nummer 1. Daher statt neue zu schaffen Atomicinteger Sie nur den Wert zurücksetzen, indem Methode set(int value) (siehe javadoc für weitere Informationen):

counter.set(0); 

Dieser Ansatz wird normalerweise verwendet, weil es schneller sein sollte und Sie sicher sind, dass es Thread-sicher ist (auch, warum etwas tun, was bereits getan ist).

+0

Können Sie meinen Code bearbeiten, um das zu zeigen? – Aiden

+0

Oh, und ich habe es nicht bemerkt - du benutzt lang, also benutze [AtomicLong] (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicLong.html) anstelle von AtomicInteger. Das tut mir leid. – mrek

+0

Vielen Dank !!!. Ich werde es versuchen – Aiden

0

Wenn zwei Threads eine synchronisierte Methode in einer Klasse ausführen, stehen sie nur in Konflikt, wenn sie über dieselbe Instanz des Objekts arbeiten. In diesem Fall kann jeweils nur ein Thread die Methode ausführen. Der andere Thread muss warten, bis der erste den Methodenaufruf beendet hat.

Beachten Sie, dass ein Thread seine Sperren hält, auch wenn es in den Ruhezustand versetzt wird. Daher sollten Sie so wenige Zeilen Code wie möglich synchronisieren.

Dies könnte erreicht werden, indem ein Codeblock (oder sogar eine einzelne Codezeile) anstelle von ganzen Methoden synchronisiert wird.

class MyClass{ 
    public void myMethod(){ 
     ... 
     synchronized(this){ 
      // All code in this block is synchronized. 
     } 
     .... 
    } 
} 

Wenn Sie die Operation über verschiedene Instanzen synchronisieren müssen, sollten Sie die Methode statisch machen. Sobald dies erledigt ist, können Sie die ganze Methode synchronisieren:

class MyClass{ 
    public static synchronized void myMethod(){ 
     ...    
    } 
} 

oder einen Block von Code innerhalb der Methode:

class MyClass{ 
    public static void myMethod(){ 
     ... 
     Class c1 = Class.forName("MyClass"); 
     synchronized(c1){ 
      // All code in this block is synchronized. 
     } 
     .... 
    } 
} 
+0

Kann ich ganze Methode synchronisieren? Methode wird von einer Haupt-Service-Klasse aufgerufen, die von Framework-Klassen aufgerufen wird. Ich bin sehr verwirrt, wenn mehrere Instanzen der Klasse erstellt werden, aber eine Sache, die ich weiß, jeder Service-Aufruf ist eine neue Transaktion, so dass mehrere Objekte erstellt werden. Funktioniert die Synchronisierungsmethode noch? – Aiden

+0

Ich habe die Antwort nach Ihrem Kommentar bearbeitet – debus

+0

GREAT !!! Ich werde es versuchen!!! – Aiden

Verwandte Themen