Pregunta / volatile

Hola a todos, pues de nuevo con más dudas, esta ves me acosa la incógnita de como usar volatile, revise varias ligas en esta: http://codeidol.com/java/java-concurrency/Cancellation-and-Shutdown/Task... encontré este ejemplo, uno de los más completos:

Lo copio y pego agradeciendo a los autores.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package volatilTest;

import static java.util.concurrent.TimeUnit.SECONDS;
import java.math.BigInteger;
//import java.util.*;
import java.util.ArrayList;
import java.util.List;
//import java.util.concurrent.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import net.jcip.annotations.*;
/**
 * PrimeGenerator
 *
 * Using a volatile field to hold cancellation state
 *
 * @author Brian Goetz and Tim Peierls
 */

@ThreadSafe
public class PrimeGenerator implements Runnable {

    private static ExecutorService exec = Executors.newCachedThreadPool();
    @GuardedBy("this")
    private final List<BigInteger> primes = new ArrayList<BigInteger>();
    private volatile boolean cancelled;

    public void run() {
        BigInteger p = BigInteger.ONE;
        while (!cancelled) {
            p = p.nextProbablePrime();
            synchronized (this) {
                //System.out.println(p);
                primes.add(p);
            }
        }
    }

    public void cancel() {
        cancelled = true;
    }

    public synchronized List<BigInteger> get() {
        return new ArrayList<BigInteger>(primes);
    }

    static List<BigInteger> aSecondOfPrimes() throws InterruptedException {
        PrimeGenerator generator = new PrimeGenerator();
        exec.execute(generator);
        try {
            SECONDS.sleep(1);
        } finally {
            generator.cancel();
        }
        return generator.get();
    }
}

import java.math.BigInteger;

public class Main {

    public static void main(String... args) throws InterruptedException {
        PrimeGenerator primeGenerator = new PrimeGenerator();

        for (BigInteger bi : primeGenerator.aSecondOfPrimes()) {
            System.out.println("Salida: " + bi);
        }
    }
}

La cosa es que si no uso volatile me arroja el mismo resultado y creo que es por que desde la versión 5 de Java convierte las variables a volatiles automáticamente o solo las que vayan a ser modificadas (http://www.vogella.de/articles/JavaConcurrency/article.html#concurrency_...), creo entender los concepto y diferencias: por ejemplo que el manejador de memoria de la VM cambia el valor directamente y no en el buffer (o memoria intermedia), aun así me quedo con muchas dudas.

Agradecería mucho la opinión y guia de los expertos en el foro.
Y pues sigo recolectando información hasta que me compre el libro (Java Concurrency in Practice. Addison-Wesley, 2006. With Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, and Doug Lea.)

Jejeje ya de paso, me podrían decir como usar @ThreadSafe y @GuardedBy("this") y para que sirven, aun así investigare por mi cuenta :)

Gracias por su tiempo chicos bye : ).

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de rodrigo salado anaya

import net.jcip.annotations.*;

Para agregar las anotaciones faltantes.
http://mvnrepository.com/artifact/net.jcip/jcip-annotations/1.0

Imagen de ezamudio

anotaciones

@ThreadSafe y @GuardedBy no son anotaciones estándar de Java 5 ni 6 http://groups.google.com/group/jsr-305/browse_thread/thread/d23818210240...

Es muy difícil probar las variables volatile, porque necesitas hacer un acceso realmente concurrente (que dos hilos intenten modificar la variable exactamente al mismo tiempo, una volátil y una normal) y no tienes control sobre eso. La cosa es que si tienes una variable nativa que es susceptible de ser leída por dos o más hilos al mismo tiempo, te conviene usar volatile.

Imagen de ArenasMx

leyendo.....

en la gui de certificacioón SCJP en el capitulo uno habla sobre el uso de las palabras reservadas como volatile aunque los ejemplo que propone no son lo suficientemente claros para entender el uso y como lo explica ezamudio es muy muy claro

Imagen de rodrigo salado anaya

Gracias por la información.

Gracias por la información de las anotaciones @EZamudio, y pues estuve de necio y saque un ejemplo con una volátil y un no-volátil.

Saca algo como esto:

/*Output Moment:{Bef} Thread:{data-1} */  // donde Bef=before del cambio y aft=after del cambio
Volatile  :[0]  // el valor de la variable volátil y la no-volátil
NoVolatile:[0]

Este es el código de mi ejemplo:

public class Data {

    private volatile int numberVolatile;
    private int numberNoVolatile;

    public int getNumberNoVolatile() {
        return numberNoVolatile;
    }

    public void setNumberNoVolatile(int numberNoVolatile) {
        this.numberNoVolatile = numberNoVolatile;
    }

    public int getNumberVolatile() {
        return numberVolatile;
    }

    public void setNumberVolatile(int numberVolatile) {
        this.numberVolatile = numberVolatile;
    }
}

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.lang.System.out;

public class GenerateNumber implements Runnable {

    private Data data;
    private String name;
    private int time;
    private static ExecutorService exec = Executors.newCachedThreadPool();

    public GenerateNumber(Data d, String n, int t) {
        data = d;
        name = n;
        time = t;
    }

    private void printData(String moment) {
        out.println("/*Output Moment:{" + moment + "} Thread:{" + name + "} */");
        out.println("Volatile  :[" + data.getNumberVolatile() + "]");
        out.println("NoVolatile:[" + data.getNumberNoVolatile() + "]");

    }

    public void execThread() {
        exec.execute(this);
    }

    public void run() {
        while (true) {
            try {
                SECONDS.sleep(time);
            } catch (InterruptedException ex) {
                out.println(ex);
            }
            printData("Bef");
            data.setNumberVolatile(data.getNumberVolatile() + 1);
            data.setNumberNoVolatile(data.getNumberNoVolatile() + 1);
            printData("Aft");
        }
    }
}

public class Main {

    public static void main(String... args) throws InterruptedException {
        Data d = new Data();
        GenerateNumber g_1 = new GenerateNumber(d, "data-1", 1);
        GenerateNumber g_2 = new GenerateNumber(d, "data-2", 2);
        g_1.execThread();
        g_2.execThread();
    }
}

run:
/*Output Moment:{Bef} Thread:{data-1} */
Volatile  :[0]
NoVolatile:[0]
/*Output Moment:{Aft} Thread:{data-1} */
Volatile  :[1]
NoVolatile:[1]
/*Output Moment:{Bef} Thread:{data-2} */
Volatile  :[1]
NoVolatile:[1]
/*Output Moment:{Aft} Thread:{data-2} */
Volatile  :[2]
NoVolatile:[2]
/*Output Moment:{Bef} Thread:{data-1} */
Volatile  :[2]
NoVolatile:[2]
/*Output Moment:{Aft} Thread:{data-1} */
Volatile  :[3]
NoVolatile:[3]
/*Output Moment:{Bef} Thread:{data-1} */
Volatile  :[3]
NoVolatile:[3]
/*Output Moment:{Aft} Thread:{data-1} */
Volatile  :[4]
NoVolatile:[4]
/*Output Moment:{Bef} Thread:{data-2} */
Volatile  :[4]
NoVolatile:[4]
/*Output Moment:{Aft} Thread:{data-2} */
Volatile  :[5]
NoVolatile:[5]
/*Output Moment:{Bef} Thread:{data-1} */
Volatile  :[5]
NoVolatile:[5]

Y pues si como me lo dices, esta cañón poder probar volatile, por el momento creo que me quedo con lo que entiendo de esto.
También esta interesante que no se puede usar volatile con operadores ++ y --, pero eso ya es otra onda ( por que en realidad son más de una operación , más no atómica), en el ejemplo aun que se incrementan las variables se hace de un jalón: data.getNumberVolatile() + 1.

Pues muchas gracias por el tiempo, opinión y si te surge (a quien sea ) una idea de como probarlo en algún momento te lo agradecería me lo compartieras. Bye y suerte a todos : ).