Preguntas y tips sobre la programación en Java
pregunta básica acerca de la clase Integer.
¿Cómo puedo modificar el valor de una instancia de Integer? El API no ofrece ningún método setValue
Las clases Integer, String, Float, Double, Byte, Long, Short, Boolean, y Character son ejemplos de clases inmutables. Por definición, no se puede alterar el valor de un objeto inmutable después de su construcción.
En Java, una clase como Integer actúa como un simple wrapper alrededor de su contraparte primitiva -en este caso, int. Los wrappers que uno encuentra en java.lang nos permiten tratar a los tipos primitivos como si fueran objetos. Así pues, por ejemplo, no se puede incluir un int en un Vector sin envolverlo primero en un objeto Integer.
La ventaja principal que ofrecen un objeto inmutable es que intrísecamente es thread safe. Como un thread no puede alterar el objeto, no se necesita proteger de accesos de threads concurrentes.
Desde luego que si necesitamos alterar las instancias de Integer estamos en problemas. Sin embargo, podemos escribir wrappers mutables para uso de nuestros objetos. Desgraciadamente, no puedemos hacer nada con objetos de terceros que retornen instancias de java.lang.Integer.
Sé que todos mis objetos heredan el método wait que está definido en Object, sin embargo nunca lo aprovecho. ¿Qué hace ese método?
Para ilustrar la funcionalidad de este método tengamos en cuenta el siguiente código:
Object o = new Object();//cualquier objeto
synchronized(o) {
try {
otroObjeto.llamadaCualquiera();
o.wait();
objetillo.llamadita();
} catch(InterruptedException ie) {
ie.printStackTrace();
}
}
wait es un método que hace que la instancia de Thread digamos, t, que está ejecutando el código en cuestión detenga su ejecución. Hay dos instrucciones (que deben ser ejecutadas desde otro thread) que obligan a t a seguir adelante una vez que está en espera:
t.interrupt();
o.notifyAll();
Sin embargo, el comportamiento del programa es diferente en ambos casos. Si se ejecuta t.interrupt() entonces o.wait() arrojará una InterruptedException de modo que la siguiente línea que t ejecutaría es ie.printStackTrace(). Mientras que si lo que despierta a t de su espera es o. notifyAll() entonces la línea siguiente que t ejecutaría es objetillo.llamadita(). o.notifyAll() notifica a todos los threads que en ese momento estén detenidos en o.wait() que sigan adelante con su ejecución, en particular se le notifica a t.
Si se ve con cuidado el código, se verá que la llamada a o.wait() está dentro de una sección sincronizada, esto se escribió así para hacer notar que es necesario que t tenga el lock de o para poder llamarle el método o.wait(), de lo contrario wait() arrojaría una IllegalMonitorStateException. Ésta no tiene que cacharse porque extiende RuntimeException.
Así pues, podemos observar que el uso principal de o.wait() es, justamente, la espera de que una condición se cumpla en otro thread para poder seguir ejecutando el código en cuestión. Dos cosas más debemos mencionar: primero, hay dos firmas más del método wait, a saber, wait(long timeout), y o.wait(long timeout, int nanos). Estos métodos simplemente hacen esperar al thread de ejecución un máximo de timeout milisegundos y, si nanos es mayor o igual a 500 entonces el thread esperará timeout + 1 milisegundos como máximo. Si se da el timeout la ejecución continúa como si el thread hubiera despertado por una llamada a o.notifyAll(). No hay manera de saber si un thread salió de un wait por el timeout o por una notificación.
Segundo, Object además ofrece el método notify() que solamente avisa a uno (si lo hay) de los threads que estén esperando por una notificación en el o.wait() del objeto en cuestión. Sin embargo, nosotros no puedemos saber qué thread será avisado, sólo sabemos que uno de todos los threads en espera será sacado del wait set del objeto en cuestión.