This article from: http://blog.csdn.net/zyplus/article/details/6672775
After I opened a blog on csdn, I never published any article on it. It wasn't until I had a conversation with one of my predecessors that I discovered the importance of a technical blog, we are determined to build a csdn blog. But I have never found a good starting topic. Now I have a new experience in Java thread mutex and synchronization. Let's start with it.
In Java, there are no methods similar to PV operations and process mutex. Java Process Synchronization is implemented through synchronized (). It should be noted that the Java synchronized () method is similar to the mutex memory block in the operating system concept. In the object type in Java, all have a memory lock. After a thread acquires the Memory Lock, other threads cannot access the memory, so as to implement simple synchronization and mutex operations in Java. You can understand why synchronized (this) and synchronized (static
XXX). Synchronized is used to apply for a memory lock for the memory block. This keyword indicates an object of the class. Therefore, its memory lock is a mutex operation for the same object, the static member belongs to the class proprietary, and its memory space is shared by all the members of the class. This causes synchronized () to lock the static member, which is equivalent to locking the class, that is, all the members of the class are mutually exclusive. At the same time, only one thread can access the instance of the class. If you simply want to implement thread mutex in Java, it is enough to understand these basics. However, to wake up each other in threads, you need to use object. Wait () and object. nofity.
OBJ. wait (), and obj. notify () must be used with synchronized (OBJ), that is, wait. It is used with notify to operate on the OBJ lock that has been obtained. In terms of syntax, It is obj. wait (), obj. Y must be in synchronized (OBJ ){...} within the statement block. In terms of function, wait means that the thread actively releases the object lock after obtaining the object lock, and the thread sleep. You can continue to obtain the object lock and continue to execute the lock until notify () of an object is invoked by another thread. The corresponding notify () is the wake-up operation on the object lock. However, it is important to note that after policy () is called, the object lock is not released immediately, but after the execution of the corresponding synchronized () {} statement block ends and the lock is automatically released, JVM randomly selects a thread from the thread of the wait () object lock, assigns it an object lock, wakes up the thread, and continues execution. This provides synchronous and wake-up operations between threads. Thread. sleep () and object. both wait () and wait () can suspend the current thread and release CPU control. The main difference is that the object. wait () releases the control of the object lock while releasing the CPU.
It is not enough to understand the concept clearly. You need to test in the actual example to better understand it. Object. wait (), object. the most typical example of policy () is to print ABC in three threads. This is a typical interview question. The question requirements are as follows:
Create three threads, thread a prints 10 times a, thread B prints 10 times B, and thread C prints 10 times C. The thread must run simultaneously and print 10 times ABC alternately. This problem can be easily solved using the wait () and notify () of the object. The Code is as follows:
public class MyThreadPrinter2 implements Runnable { private String name; private Object prev; private Object self; private MyThreadPrinter2(String name, Object prev, Object self) { this.name = name; this.prev = prev; this.self = self; } @Override public void run() { int count = 10; while (count > 0) { synchronized (prev) { synchronized (self) { System.out.print(name); count--; self.notify(); } try { prev.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws Exception { Object a = new Object(); Object b = new Object(); Object c = new Object(); MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a); MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b); MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c); new Thread(pa).start(); new Thread(pb).start(); new Thread(pc).start(); } }
Let's first explain the overall idea. In a general sense, this problem is a synchronous wake-up operation between three threads, the main purpose is threada-> threadb-> threadc-> threada executes three threads cyclically. To control the thread execution sequence, you must determine the wake-up and wait sequence. Therefore, each thread must hold two Object locks at the same time to continue execution. An object lock is Prev, which is the object lock held by the previous thread. Another is its own object lock. The main idea is that in order to control the execution sequence, you must hold the prev lock first, that is, the previous thread must release its own object lock and then apply for its own object lock. when both of them are printed, call self first. Y () releases its own object lock, wakes up the next waiting thread, and then calls Prev. wait () releases the prev object lock, terminates the current thread, and is awakened again after the loop ends. Run the above Code and you will find that three threads print ABC cyclically for 10 times. The main process of running the program is that the thread runs first, holds the C and A Object locks, releases the and C locks, and wakes up B. Thread B waits for lock a, apply for lock B again, print lock B, release lock B, lock a, wake up lock C, thread C waits for lock B, apply for Lock C again, and print lock C, then release the C and B locks to wake up. It seems that there is no problem, but if you think about it carefully, you will find that there is a problem, that is, the initial condition. The three threads start in the order of A, B, and C, according to the previous thinking, a wakes up B, B wakes up C, and C wakes up. However, this assumption depends on the thread scheduling and execution sequence in JVM. Specifically, after threada is started in the main thread, it must be completed in threada, in Prev. when wait () waits, the thread is switched back to start threadb. After threadb is executed. when wait () waits, It switches back to the main thread and starts threadc. Only when the JVM runs in the running sequence of this thread can the output result be correct. This depends on the specific implementation of JVM. Consider one of the following situations: if the main thread executes a after starting a and switches back to the main thread during the process, it starts threadb and threadc, because thread A has not released self. notify, that is, B needs to wait at synchronized (prev), while C calls synchronized (prev) to obtain the object lock on B. In this way, after calling a, threadb obtains the prev, that is, the object lock of A, and the execution condition of threadc is met. It prints C and releases C, and the object lock of B. At this time, threadb has the running condition and prints B, that is, the loop is changed to acbacb. In this case, you can take the initiative to release the CPU in the run to simulate. The Code is as follows:
public void run() { int count = 10; while (count > 0) { synchronized (prev) { synchronized (self) { System.out.print(name); count--; try{ Thread.sleep(1); } catch (InterruptedException e){ e.printStackTrace(); } self.notify(); } try { prev.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
The printed result after running is changed to acbacb. To avoid such uncertainty related to JVM scheduling. Three threads A, B, and C need to be started in a definite order. The final code is as follows:
public class MyThreadPrinter2 implements Runnable { private String name; private Object prev; private Object self; private MyThreadPrinter2(String name, Object prev, Object self) { this.name = name; this.prev = prev; this.self = self; } @Override public void run() { int count = 10; while (count > 0) { synchronized (prev) { synchronized (self) { System.out.print(name); count--; try{ Thread.sleep(1); } catch (InterruptedException e){ e.printStackTrace(); } self.notify(); } try { prev.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws Exception { Object a = new Object(); Object b = new Object(); Object c = new Object(); MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a); MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b); MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c); new Thread(pa).start(); Thread.sleep(10); new Thread(pb).start(); Thread.sleep(10); new Thread(pc).start(); Thread.sleep(10); } }
In this way, the problem can be solved perfectly. This example also describes many theories and concepts, such as obj. wait (), obj. notify () and so on. It is easy to understand, but in actual application, it is often a problem. It requires a deeper understanding. In the process of solving the problem, we constantly learn more about the concept.