2017-12-22 7 views
0

Ich habe den folgenden Code verhindern:Wie Kontextwechsel in einem kritischen Abschnitt

import java.util.ArrayList; 

public class main { 
    final static Object lock= new Object(); 
    public static void main(String[] args) { 

     for (int i = 0; i < 100000; i++) { 

      System.out.println("-------"); 
      finish finished = new finish(false); 
      ArrayList<Boolean> arr = new ArrayList<>(); 

      Thread t1 = new Thread(() -> { 
       System.out.println(Thread.currentThread().getId() + " Is setting"); 
       finished.setFinished(true); 

      }); 


      t1.start(); 
      synchronized (lock){ 
       if (finished.isFinished == false) { 
        System.out.println(Thread.currentThread().getId() + " Is adding"); 
        arr.add(new Boolean(finished.isFinished)); 
       } else { 
        System.out.println("Done"); 
       } 
      } 


      System.out.println("The length of array is " + arr.size()); 
      if (arr.size() > 0) { 
       System.out.println("The val of array is " + arr.get(0)); 
      } 
     } 
    } 
} 

class finish { 
    public boolean isFinished = false; 

    public finish(boolean finished) { 
     this.isFinished = finished; 
    } 

    public void setFinished(boolean finished) { 
     this.isFinished = finished; 

    } 

} 

Ich erwarte die folgende Ausgabe zu erhalten:

Die Länge des Arrays ist 1
Die val Falsch des Arrays ist

oder

Fertig

Es ist der Fall die meiste Zeit. Aber manchmal ist die Ausgabe:

Die Länge des Arrays ist 1
Die val von Array wahr ist

Es bedeutet, dass es ein Kontextschalter im kritischen Abschnitt war. Ich habe versucht, den Code auf ein Objekt zu synchronisieren, aber es hat nicht geholfen. Es ist ein klassisches Synchronisationsproblem, das ich aber nicht lösen konnte. Vielleicht sollte ich Atomobjekte verwenden, aber ich habe keine Ahnung, wie sie in diesem Fall helfen würden. Oder vielleicht bin ich zu hart mit Java, und ich sollte es nicht in einer for-Schleife testen? Ich führe dieses Beispiel auf einem Linux-Betriebssystem. Ich denke meine Synchronisation macht keinen Sinn. Aber ich weiß nicht, wie ich es lösen soll.

+0

Zeigen Sie uns Ihren Versuch der Synchronisierung. –

+0

Sie synchronisieren nicht beide Threads, daher können Sie das gewünschte Ergebnis nicht garantieren. –

Antwort

2

Es ist überhaupt nicht klar, was Ihr Beispielcode zu tun versucht, aber wenn Sie auf das Ende des Threads warten möchten, verwenden Sie t1.join() und behandeln Sie die InterruptedException, die dies wirft. Außerdem sollte finished ein AtomicBoolean sein, wenn Sie es in mehr als einem Thread verwenden.

Aber alles in allem ist der Code ziemlich problematisch und spiegelt nicht das reale Szenario wider, mit dem Sie umgehen wollen.

0

In diesem Code lesen Sie die gleiche Variable zweimal, was die Möglichkeit der Änderung ermöglicht. Die einfachste Lösung ist, es nur einmal zu lesen.

boolean isFinished = finished.isFinished; 
if (isFinished) { 
    System.out.println("Done"); 
} else { 
    System.out.println(t1 + " Is adding"); 
    arr.add(isFinished); 
} 
Verwandte Themen