The following code demonstrates how to synchronize specific class methods:
Copy the code code as follows:
package mythread;
public class SyncThread extends Thread
{
private static String sync = "";
private String methodType = "";
private static void method(String s)
{
synchronized (sync)
{
sync = s;
System.out.println(s);
while (true);
}
}
public void method1()
{
method("method1");
}
public static void staticMethod1()
{
method("staticMethod1");
}
public void run()
{
if (methodType.equals("static"))
staticMethod1();
else if (methodType.equals("nonstatic"))
method1();
}
public SyncThread(String methodType)
{
this.methodType = methodType;
}
public static void main(String[] args) throws Exception
{
SyncThread sample1 = new SyncThread("nonstatic");
SyncThread sample2 = new SyncThread("static");
sample1.start();
sample2.start();
}
}
The running results are as follows:
Copy the code code as follows:
method1
staticMethod1
Many readers may be surprised to see the above running results. In the above code, the method1 and staticMethod1 methods use the static string variable sync for synchronization. Only one of these two methods can be executed at the same time, and both methods will execute the infinite loop statement in line 014. Therefore, the output result can only be one of method1 and staticMethod1. But this program outputs both strings.
The reason for this result is very simple, we will know it by looking at line 012. It turns out that the value of sync is changed in this line. Here I want to talk about the String type in Java. The String type is different from other complex types in Java. When using a String type variable, as long as you assign a value to the variable once, Java will create a new instance of the String type. As shown in the following code:
Copy the code code as follows:
String s = "hello";
System.out.println(s.hashCode());
s = "world";
System.out.println(s.hashCode());
in the code above. The hashCode values of the first s and the reassigned s are different. Since creating an instance of the String class does not require the use of new, when synchronizing a String type variable, be careful not to assign a value to this variable, otherwise the variable will not be synchronized.
Since a new instance for sync has been created in line 012, assuming method1 is executed first, when method1 executes the code in line 013, the value of sync is no longer the original value, and method1 still locks the sync variable. The initial value. At this time, staticMethod1 happens to be executed to synchronized(sync). The sync to be locked in the staticMethod1 method and the sync locked by the method1 method are no longer the same. Therefore, the synchronization of the two methods has been destroyed.
The solution to the above problem is of course to remove line 012. This line is added to this example just to illustrate that when using class variables to synchronize methods, if the value of the synchronization variable is changed in the synchronized block, the synchronization between methods will be destroyed. In order to completely avoid this situation, you can use the final keyword when defining synchronization variables. For example, line 005 in the above program can be changed to the following form:
Copy the code code as follows:
private final static String sync = "";
After using the final keyword, sync can only assign a value to it when it is defined, and it cannot be modified later. If sync is assigned a value elsewhere in the program, the program will not compile. In development tools such as Eclipse, prompts will be given directly in the wrong place.
We can understand synchronized blocks from two perspectives. If understood from the perspective of class methods, the corresponding methods can be synchronized through class variables. If you understand it from the perspective of class variables, you can use synchronized blocks to ensure that a class variable can only be accessed by one method at the same time. No matter which angle you understand it from, their essence is the same, which is to use class variables to obtain synchronization locks and achieve synchronization through the mutual exclusion of synchronization locks.
Note: When using synchronized blocks, you should be aware that synchronized blocks can only use objects as its parameters. If it is a simple type of variable (such as int, char, boolean, etc.), synchronized cannot be used for synchronization.