2013-04-05 23 views
12

Zgodnie z JSR-133 niezmienne obiekty są bezpieczne dla wątków i nie wymagają synchronizacji. Jednak jest to możliwe do aktualizacji wartości pól końcowych przy użyciu odbicia:Jak działa odbicie i niezmienność?

package com.stackoverflow; 

import java.lang.reflect.Field; 

public class WhatsGoingOn { 

    static class Immutable { 
     private final int value; 

     public Immutable(int value) { 
      this.value = value; 
     } 

     public int getValue() { 
      return value; 
     } 
    } 

    public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { 
     final Immutable immutable = new Immutable(Integer.MIN_VALUE); 

     final Field f = Immutable.class.getDeclaredField("value"); 
     f.setAccessible(true); 

     System.out.println(immutable.getValue()); 
     f.set(immutable, Integer.MAX_VALUE); 
     System.out.println(immutable.getValue()); 
    } 
} 

Biorąc pod uwagę ilość ram (wiosna i hibernacji to tylko kilka), które opierają się na refleksji Jestem ciekaw, co robi specyfikacja mówi o tym scenariuszu. Na przykład. jeśli wstawię aktualizację pola do zsynchronizowanego bloku, to zagwarantuje to widoczność w innych wątkach, lub wartość zostanie zapisana w pamięci podręcznej, zgodnie ze specyfikacją końcową.

http://download.oracle.com/otndocs/jcp/memory_model-1.0-pfd-spec-oth-JSpec/

Odpowiedz

5

Obiekt uważa się za niezmienny, jeśli jego stan nie może się zmienić po jego zbudowaniu. http://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html

Używasz tego przedmiotu jako zmienny ponieważ zmieniają swój stan.

To prawda, że ​​użycie Reflection przełamuje niezmienność w sposób opisany w samouczku, ponieważ można go użyć do zmiany niestałych pól końcowych.

Przykładem odbicie odporne niezmiennego obiektu byłyby następujące:

static class Immutable { 
    // This field is a constant, and cannot be changed using Reflection 
    private final int value = Integer.MIN_VALUE; 

    public int getValue() { 
     return value; 
    } 
} 

public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { 
    final Immutable immutable = new Immutable(); 

    final Field f = Immutable.class.getDeclaredField("value"); 
    f.setAccessible(true); 

    System.out.println(immutable.getValue()); 
    f.set(immutable, Integer.MAX_VALUE); 
    System.out.println(immutable.getValue()); 
} 

W tym przypadku nasz test odbicie nie powiedzie, a wartość pozostanie Integer.MIN_VALUE. Ale hej, zawsze możemy użyć natywnego kodu lub edytora pamięci, aby zmienić tę wartość na coś innego.

Jeśli sięgniesz tak daleko w hackowanie z refleksją, równie dobrze możesz nie nazwać finału pola i podać metody manipulowania nim.

4

Wszystkie zakłady są wyłączone z refleksji jeśli nalegać na kontrolę dostępu do przełączania się i robić niegrzeczne rzeczy.

Stałe statyczne są zwykle wyświetlane w czasie kompilacji, więc zmiana ich wartości prawdopodobnie nie miałaby żadnego wpływu. Wynik naprawdę zależy od tego, jak inteligentny jest optymalizator podczas kompilacji i jak sprytny jest kompilator JIT w czasie wykonywania.

Wynik końcowy: "Tu bądźcie smokami, bójcie się wszystkich, którzy ośmielą się tu deptać!"

3

błędy spójności pamięci zdarzyć się w tym scenariuszu:

1 Wątek 1 odczytuje pole z b1.getField1() i dostaje 1

2 gwint 2 zmienia pole z b1.setField1 (2)

3 teraz, gdy wątek 1 wywoła b1.getField1(), może ponownie uzyskać 1, ponieważ w przypadku braku synchronizacji JVM może zoptymalizować to wywołanie i zwrócić buforowaną wartość.

Ale jeśli inicjowana jest zmienny fasoli tylko raz podczas instancji (ewentualnie z refleksji, jak wiosna robi pojemniku) i innych wątków będzie czytać ją tylko po inicjalizacji, nie będzie żadnych błędów spójności pamięci nawet bez synchronizacja

Te same zasady odnoszą się do niezmiennych obiektów, gdy zmieniasz ich pola z odbiciem.

Powiązane problemy