Wednesday, January 22, 2003
I suddenly found that there are still many things that need me to understand, such as Synchronized this keyword. Because when I was created in the study of the connection pool, I found that if I didn't figure out this concept, I couldn't go on. So I decided to cool your interest to Socket first, and go back to see Synchronized.
After watching the Think in Java, I feel that it is still effective. I should write down and deepen my impression. I feel that my brain can reuse very low, always need to generate new memory objects, thus consumed many repetitive labor. So records , Analysis, summing up such similar work should be much better.
To understand the usage of Synchronized, you must first know what problem is used to solve it. Since Synchronized is the meaning of synchronization, then it is of course to solve the problem of disagreement. Let's take an unaptified example to demonstrate possible The problem.
In this example, we will create two thread classes. A TWOCOUNTER, its job is accumulating the two counter variables, from 1st, you will think about it, we are using it to implement a synchronization. Another A object called Watcher, as the name suggests, it is responsible for checking if the value of the two counters in the Twocounter thread is equal, it seems to be meaningless work, because since it is accumulated, then two How can the value of a counter may not be equal??
However, the fact is not the case. Let's first look at the program. Before watching this program, we'd better flip THINK IN JAVA 14.2.1, and my program is actually simplified according to the example given in this section. The main class is changed to Sharing2
Class Twocounter Extend1 = 0, Count2 = 0; Private Boolean Started = False; Public Void Start () {if (! Started) File: / / Prevents Multiple Tune Start Method {Started = True; Super.Start ();}} public void run () {while (true) {count1 ; file: // If Twocounter runs to this time, the CPU time film is assigned to Watcher, then this time Watcher reads two The value of the counter will be different, this possibility exists. "This is caused by the essence of thread - they can hang (pause) at any time. So in the execution time of the above two lines, there is sometimes the execution pause. At the same time, the Watcher thread is just right. It is just compared at this time, causing an unequal case in the counter. "(Think in java) count ; system.out.println (" count1 = " count1 ", count2 = " count2); try {Sleep (500 } Catch (InterruptedException E) {}}}
Public void synchtest () {Sharing2.incrementAccess (); if (count1! = count2) system.out.println ("unsynched"); // Once you find unsynchronization, immediately display}}
Class Watcher Extends Thread {Private Sharing2 P; Public Watcher (Sharing2 P) {THIS.P = P; Start ();} Public Void Run () {while {pssynchtest (); try {Sleep (500); } catch (InterruptedException e) {}}}} public class Sharing2 {TwoCounter s; private static int accessCount = 0; public static void incrementAccess () {accessCount ; System.out.println ( "accessCount =" accessCount);} public Static void main (string [] args) {Sharing2 aaa = new sharing2 (); aaa.s = new twocounter (); aaa.s.start (); // Open Twocounter thread new Watcher (AAA); // Open Watcher Thread}}}
The above annotations are very clear, there is a case where it is not synchronized. But strangely, when I am running, I have never encountered the case of disagreement, then there is only one situation, that is, count1 and count2 Almost simultaneous, Watcher threads are inserted, but why there is definitely something that is not synchronized after the program above the THINK IN Java? The principle of the two programs is exactly the same, the only difference is that my program is simple. And running under the command line, not using the GUI. Is it because running using the applet, run overhead in the Windows main window, make Watcher organic? So I tried it between count1 and count2 A loop statement, the human increased gap, is to make Watcher good inserted, resulting in monitoring count1 does not equal the situation of count2, realizing disagreement. Modified programs are like this ... COUNT1 ; For (int i = 0; i <5000; i ); count2 ; ......
OK! Run the program, soon there is no synchronization phenomenon, this seems to prove that the analysis I just was correct. But strangely, after the output of unsynchrized, there will be no longer appeared in the future, that is, said, The Watcher thread only detected two counters count. This made me feel a bit depressed, is it a coincidence or inevitable? Maybe time is too short, wait until you must have unsynchrized output.
Forget it, this problem is put down, we continue. Since there is a problem that there is a problem, it is clear that the solution is synchronized: turn Twocounter's RUN method and synchtest method to synchronize method. What does it mean to do? What is the benefits? Please refer to the 14.2.2 section of Think in Java, which is very detailed and thorough. Especially for the monitor, it is the concept of object locks we usually say, and the book is very clear.
In short, the code that needs to be modified is as follows: Class Twocounter Extends thread {public synchronized void () {while (true) {count1 ; count2 ; system.Println ("count1 =" count1 ", count2 =" count2); try {sleep (500);} catch (InterruptedException e) {}}} public synchronized void synchTest () {Sharing2.incrementAccess (); if (! count1 = count2) System.out.println ( "Unsynched"); // Once you find it is not synchronized, immediately display}}}
Other non-written, indicating that from the problem to solve it is very simple, huh, huh. We note that both Run () or synchtest () is "synchronous". If you only synchronize one of the methods, then the other can freely ignore the lock of the object and can be called. So you must remember an important rule: For all methods accessing a key shared resource, you must set them to synchronized, otherwise it will not work properly.
Now I have encountered a new problem. Watcher2 will never see what is going on because the entire Run () method is set to "synchronize". And because you have to run Run () for each object, the lock can never be opened, and synchtest () will never be called. It can see this result because AccessCount has not changed at all.
In order to solve this problem, one of the ways we can take is to isolate some of the code in Run (). I want to use this part of the code that is isolated from the "critical area", and uses the Synchronized keyword in different ways to set a critical area. Java provides support for key areas via "synchronization block"; this time, we specifically use the synchronized keyword to synchronize the code in which the enclosed code is used. As follows:
Synchronized (syncobject) {// this code can be subject at a time, assuming all // threads respect syncobject's lock}
Before you can enter the synchronization block, you must get the lock on Synchobject. If there are other threads to get this lock, the block cannot be entered, and must wait to release the lock. The Synchronized keyword can be removed from the entire run (), and the two key lines are enclosed with a synchronization block to complete the modification of the Sharing2 example. But what object should be used as a lock? That object has been marked by synchtest () - that is, the current object (this)! So the modified Run () method is like this:
File: // Note No synchronized key Public void Run () {while (true) {synchronized (this) {count1 ; count2 ;} system.out.println ("count1 =" count1 ", count2 =" count2 ); Try {Sleep (500);} catch (interruptedException e) {}}} file: // Note, SYNCHTEST () still has a synchronized keyword, think about why
In this way, the Synchtest method can be called, and we can also see the change of AccessCount.