Build three threads, a thread prints 10 times A, a thread prints 10 times b,c thread prints 10 times C, requires the thread to run concurrently, and prints 10 times the ABC.
This problem can be easily solved with object's Wait (), notify ().
Public classMyThreadPrinter2ImplementsRunnable {PrivateString name; PrivateObject prev; PrivateObject Self; PrivateMyThreadPrinter2 (String name, Object prev, object self) { This. Name =name; This. prev =prev; This. Self =Self ; } @Override Public voidrun () {intCount = 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 voidMain (string[] args)throwsException {Object a=NewObject (); Object b=NewObject (); Object C=NewObject (); MyThreadPrinter2 PA=NewMyThreadPrinter2 ("A", C, a); MyThreadPrinter2 PB=NewMyThreadPrinter2 ("B", A, b); MyThreadPrinter2 PC=NewMyThreadPrinter2 ("C", B, c); NewThread (PA). Start (); NewThread (Pb). Start (); NewThread (PC). Start (); } }
First to explain the overall idea, from the big direction, the problem is a three-way synchronous wake-up operation, the main purpose is to Threada->threadb->threadc->threada loop to execute three threads.
In order to control the order in which threads are executed, it is necessary to determine the order of wake-up and wait, so 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. There is also a lock on the object itself. The main idea is that in order to control the order of execution, you must first hold the Prev lock, but also the previous thread to release its own object lock, and then to apply their own object lock, both print, and then first call Self.notify () to release their object lock, wake up the next waiting thread, Call Prev.wait () to release the Prev object lock, terminate the current thread, wait for the loop to end and wake again.
Running the above code, you can find that three threads cycle to print ABC, a total of 10 times. The main process of running the program is a thread first run, hold C,a object lock, Release A,c lock, Wake B. Thread B waits for a lock, then applies a b lock, then prints B, then releases the B,a lock, wakes C, thread C waits for a B lock, then applies a c lock, then prints C, then releases the c,b lock, wakes a.
There seems to be no problem, but if you think about it, you will find that there is a problem, that is, the initial conditions, three threads in accordance with the a,b,c sequence to start, according to the previous thinking, a wake-up b,b wake C,c and then wake A.
However, this assumption relies on the sequence in which the JVM threads are dispatched and executed. Specifically, after the main thread starts Threada, it needs to be executed at Threada, when the prev.wait () waits, then the thread starts threadb,threadb execution, and when the prev.wait () waits, the main thread is cut back. To start THREADC, only the JVM executes in the order that the thread runs, to ensure that the output is correct. This relies on the specific implementation of the JVM.
Consider a situation where the following is true: if the main thread executes a after starting a, the main thread is started, and THREADB,THREADC is initiated, and since the a thread has not yet released Self.notify, that is, B needs to wait at synchronized (prev). At this point, C calls synchronized (prev) to acquire the object lock on B. In this way, after a call, at the same time threadb get the prev is a object lock, THREADC execution conditions have been satisfied, will print C, then release C, and B object lock, then threadb have the operating conditions, will print B, that is, the cycle into ACBACB. In this case, the simulation can be done by actively releasing the CPU in run. The code is as follows:
Public voidrun () {intCount = 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 (); } } } }
After the run, the print results become ACBACB. To avoid this uncertainty related to JVM scheduling. The a,b,c three threads need to be started in a certain order, with the final code as follows:
Public classMyThreadPrinter2ImplementsRunnable {PrivateString name; PrivateObject prev; PrivateObject Self; PrivateMyThreadPrinter2 (String name, Object prev, object self) { This. Name =name; This. prev =prev; This. Self =Self ; } @Override Public voidrun () {intCount = 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 voidMain (string[] args)throwsException {Object a=NewObject (); Object b=NewObject (); Object C=NewObject (); MyThreadPrinter2 PA=NewMyThreadPrinter2 ("A", C, a); MyThreadPrinter2 PB=NewMyThreadPrinter2 ("B", A, b); MyThreadPrinter2 PC=NewMyThreadPrinter2 ("C", B, c); NewThread (PA). Start (); Thread.Sleep ( Ten); NewThread (Pb). Start (); Thread.Sleep ( 10); NewThread (PC). Start (); Thread.Sleep ( Ten); } }
Practice Java Wait (), notify (), sleep Method--a multi-threaded face question