2016-09-28 3 views
1

Ich verstand den Unterschied zwischen flüchtigen und statischen Keywords auf Variablen.Volatile Schlüsselwort ohne statische funktioniert nicht wie erwartet

statische Variablen können durch verschiedene Instanzen geändert werden, während flüchtige Variablen durch verschiedene Threads geändert werden können.

Aber das folgende Programm (kopiert aus dem Internet und wenig geändert) hängt, wenn ich das statische Schlüsselwort für MY_INT Variable entfernen.

Das Update auf Variable MY_INT sollte von anderen Threads auch ohne statisches Schlüsselwort gesehen werden. Aber wenn ich statische entfernen, hängt es.

Bitte helfen Sie mir, dieses Problem zu verstehen.

public class PrintOddAndEven extends Thread { 
    static volatile int i = 1; 

    Object lock; 

    PrintOddAndEven(Object lock) { 
     this.lock = lock; 
    } 

    public static void main(String ar[]) { 
     Object obj = new Object(); 
     PrintOddAndEven odd = new PrintOddAndEven(obj); 
     PrintOddAndEven even = new PrintOddAndEven(obj); 
     odd.setName("Odd"); 
     even.setName("Even"); 
     odd.start(); 
     even.start(); 
    } 

    @Override 
    public void run() { 
     while (i <= 10) { 
      if (i % 2 == 0 && Thread.currentThread().getName().equals("Even")) { 
       synchronized (lock) { 
        System.out.println(Thread.currentThread().getName() + " - " + i); 
        i++; 
        lock.notify(); 
       } 
      } 
      if (i % 2 == 1 && Thread.currentThread().getName().equals("Odd")) { 
       synchronized (lock) { 
        System.out.println(Thread.currentThread().getName() + " - " + i); 
        i++; 

        try { 
         lock.wait(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
     } 
    } 
} 
+1

Mögliche Duplikate von [Verwenden Sie jemals das flüchtige Schlüsselwort in Java?] (Http://stackoverflow.com/questions/106591/do-you-ever-use-the-volatile-keyword-in-java) – xenteros

+0

@xenteros Nein, dies ist ein Duplikat einer Frage, die nach der Bedeutung von 'statisch' fragt. –

Antwort

1

Ihr Fehler ist auf die Tatsache zurückzuführen, dass, wenn Sie das static Schlüsselwort aus dem i Feld entfernen, werden Sie eine haben verschiedene Feld ipro Instanz von PrintOddAndEven so hier, wie Sie 2 Instanzen haben, können Sie haben 2 verschiedene Felderi so dass der Even Thread wird für immer Schleife als i ist nie verändert und der Odd Thread wartet für immer aus dem gleichen Grund. Wenn Sie das Feld als static deklarieren, teilen sich die Threads das gleiche Feldi, so dass Sie Ihren Fehler nicht stellen.

Sie sollten eine eigene Klasse erstellen, die Ihre Zähler halten wird und eine Instanz davon als Objektmonitor verwenden, die Sie zwischen den PrintOddAndEven Fällen als nächstes teilen:

public class MyClass { 
    volatile int i = 1; 
} 

public class PrintOddAndEven extends Thread { 

    MyClass lock; 

    PrintOddAndEven(MyClass lock) { 
     this.lock = lock; 
    } 

    public static void main(String[] args) throws Exception { 
     MyClass obj = new MyClass(); 
     PrintOddAndEven odd = new PrintOddAndEven(obj); 
     PrintOddAndEven even = new PrintOddAndEven(obj); 
     odd.setName("Odd"); 
     even.setName("Even"); 
     odd.start(); 
     even.start(); 
    } 

    @Override 
    public void run() { 
     while (lock.i <= 10) { 
      if (lock.i % 2 == 0 && Thread.currentThread().getName().equals("Even")) { 
       synchronized (lock) { 
        System.out.println(Thread.currentThread().getName() + " - " + lock.i); 
        lock.i++; 
        lock.notify(); 
       } 
      } 
      if (lock.i % 2 == 1 && Thread.currentThread().getName().equals("Odd")) { 
       synchronized (lock) { 
        System.out.println(Thread.currentThread().getName() + " - " + lock.i); 
        lock.i++; 

        try { 
         lock.wait(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
     } 
    } 
} 

Wenn Sie haben Nur ein Zähler, Sie könnten auch eine Instanz der Klasse AtomicInteger als Zähler und Objektmonitor verwenden. Der Code ist der gleiche wie oben, nur dass Sie eine Instanz mit new AtomicInteger(1) erstellen, um den Zähler auf 1 zu initialisieren, und dann get() verwenden, um den aktuellen Wert abzurufen, und incrementAndGet(), um den Zähler zu erhöhen.

+0

Danke. Ich hab es geschafft!! –

1

Sie haben 2 PrintOddAndEven ungerade und gerade Thread-Objekte erstellt, wenn Sie das statische Schlüsselwort aus dieser Anweisung entfernen volatile int i = 1;ich blieb nicht Klassenebene und daher hat jedes Thread-Objekt seine eigene Kopie von i, wenn ungerade Thread es ausführen, aktualisiert es die ungerade.i ++. Allerdings bleibt even.i 1, und die Bedingung wird nicht übergeben und es scheint, dass Ihr Thread ohne statische hängt.

public class PrintOddAndEven extends Thread { 
//static volatile int i = 1; 

Lock lock; 

PrintOddAndEven(Lock lock) { 
    this.lock = lock; 
} 


static class Lock { 
    volatile int i = 1; 
} 
public static void main(String ar[]) { 
    Lock obj = new lock(); 
    PrintOddAndEven odd = new PrintOddAndEven(obj); 
    PrintOddAndEven even = new PrintOddAndEven(obj); 
    odd.setName("Odd"); 
    even.setName("Even"); 
    odd.start(); 
    even.start(); 
} 

@Override 
public void run() { 
    while (lock.i <= 10) { 
     if (lock.i % 2 == 0 && Thread.currentThread().getName().equals("Even")) { 
      synchronized (lock) { 
       System.out.println(Thread.currentThread().getName() + " - " + lock.i); 
       lock.i++; 
       lock.notify(); 
      } 
     } 
     if (lock.i % 2 == 1 && Thread.currentThread().getName().equals("Odd")) { 
      synchronized (lock) { 
       System.out.println(Thread.currentThread().getName() + " - " + lock.i); 
       lock.i++; 
       try { 
        lock.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 
}} 

Auf diese Weise können Sie die Schloss und i unter den beiden Themen teilen.

Verwandte Themen