El siguiente código demuestra cómo sincronizar métodos de clase específicos:
Copie el código de código de la siguiente manera:
paquete de mitos;
la clase pública SyncThread extiende Thread
{
sincronización de cadena estática privada = "";
Tipo de método de cadena privada = "";
método privado estático vacío (String s)
{
sincronizado (sincronización)
{
sincronización = s;
System.out.println(s);
mientras (verdadero);
}
}
método de anulación pública1()
{
método("método1");
}
método estático1 vacío estático público ()
{
método ("método estático1");
}
ejecución pública vacía()
{
si (tipodemétodo.equals("estático"))
Método estático1();
de lo contrario si (methodType.equals ("no estático"))
método1();
}
SyncThread público (tipo de método de cadena)
{
this.methodType = métodoType;
}
public static void main (String[] args) lanza una excepción
{
SyncThread muestra1 = new SyncThread("nonstatic");
SyncThread muestra2 = nuevo SyncThread("estático");
muestra1.start();
muestra2.start();
}
}
Los resultados de ejecución son los siguientes:
Copie el código de código de la siguiente manera:
método1
método estático1
Muchos lectores pueden sorprenderse al ver los resultados de ejecución anteriores. En el código anterior, los métodos método1 y staticMethod1 utilizan la variable de cadena estática sync para la sincronización. Solo uno de estos dos métodos se puede ejecutar al mismo tiempo y ambos métodos ejecutarán la instrucción de bucle infinito en la línea 014. Por lo tanto, el resultado de salida solo puede ser uno de método1 y método estático1. Pero este programa genera ambas cadenas.
El motivo de este resultado es muy sencillo, lo sabremos mirando la línea 012. Resulta que el valor de sincronización se cambia en esta línea. Aquí quiero hablar sobre el tipo String en Java. El tipo String es diferente de otros tipos complejos en Java. Cuando se utiliza una variable de tipo String, siempre que asigne un valor a la variable una vez, Java creará una nueva instancia del tipo String. Como se muestra en el siguiente código:
Copie el código de código de la siguiente manera:
Cadena s = "hola";
System.out.println(s.hashCode());
s = "mundo";
System.out.println(s.hashCode());
en el código anterior. Los valores de hashCode de los primeros sy los reasignados son diferentes. Dado que crear una instancia de la clase String no requiere el uso de new, al sincronizar una variable de tipo String, tenga cuidado de no asignar un valor a esta variable, de lo contrario la variable no se sincronizará.
Dado que se creó una nueva instancia para sincronización en la línea 012, suponiendo que el método1 se ejecute primero, cuando el método1 ejecuta el código en la línea 013, el valor de sincronización ya no es el valor original y el método1 aún bloquea la variable de sincronización. . En este momento, staticMethod1 se ejecuta en sincronizado (sincronización). La sincronización que se bloqueará en el método staticMethod1 y la sincronización bloqueada por el método método1 ya no son las mismas, por lo que la sincronización de los dos métodos se ha destruido.
La solución al problema anterior es, por supuesto, eliminar la línea 012. Esta línea se agrega a este ejemplo solo para ilustrar que cuando se usan variables de clase para sincronizar métodos, si el valor de la variable de sincronización se cambia en el bloque sincronizado, la sincronización entre métodos se destruirá. Para evitar completamente esta situación, puede utilizar la palabra clave final al definir las variables de sincronización. Por ejemplo, la línea 005 en el programa anterior se puede cambiar al siguiente formulario:
Copie el código de código de la siguiente manera:
sincronización de cadena estática final privada = "";
Después de usar la palabra clave final, la sincronización solo puede asignarle un valor cuando está definida y no se puede modificar más adelante. Si a sync se le asigna un valor en otra parte del programa, el programa no se compilará. En herramientas de desarrollo como Eclipse, las indicaciones se enviarán directamente en el lugar equivocado.
Podemos entender los bloques sincronizados desde dos perspectivas. Si se entiende desde la perspectiva de los métodos de clase, los métodos correspondientes se pueden sincronizar mediante variables de clase. Si lo entiende desde la perspectiva de las variables de clase, puede usar bloques sincronizados para garantizar que solo se pueda acceder a una variable de clase mediante un método al mismo tiempo. No importa desde qué ángulo lo entienda, su esencia es la misma: utilizar variables de clase para obtener bloqueos de sincronización y lograr la sincronización mediante la exclusión mutua de los bloqueos de sincronización.
Nota: Al utilizar bloques sincronizados, debe tener en cuenta que los bloques sincronizados solo pueden utilizar objetos como parámetros. Si se trata de un tipo de variable simple (como int, char, boolean, etc.), sincronizado no se puede utilizar para la sincronización.