Reprinted from: http://www.cnblogs.com/lwbqqyumidi/p/3821389.html
Windstep
This article goes on to summarize the thread-safety issues in Java multithreading with two articles in front of multiple threads.
I. A typical Java thread safety example
1 public class ThreadTest {2 3 publicly static void main (string[] args) {4 account account = new Account ("12 3456 ", 1000); 5 drawmoneyrunnable drawmoneyrunnable = new Drawmoneyrunnable (account, 700); 6 Thread myThread1 = new Thread (drawmoneyrunnable); 7 Thread myThread2 = new Thread (drawmoneyrunnable); 8 Mythread1.start (); 9 Mythread2.start ();}11}13 class Drawmoneyrunnable implements Runnable {private account AC count;17 private Double drawamount;18 drawmoneyrunnable (account account, double drawamount) {20 Super (); this.account = account;22 This.drawamount = drawamount;23}24 public void Run () {26 if (Account.getbalance () >= drawamount) {//127 System.out.println ("Withdraw money successfully, take out the amount:" + drawamount); 28 Double balance = account.getbalance ()-drawamount;29 account.setbalance (balance); 30 System.out.println ("Balance: "+ balance)",}32}33}34 + class Account {PNS private String accountno;38 private double Bal Ance;39 () {}43 (String Accountno, double balance) {This.ac Countno = accountno;46 this.balance = balance;47}48 public String Getaccountno () {return AC countno;51}52-public void Setaccountno (String accountno) {si this.accountno = accountno;55}56 57 Public double GetBalance () {balance;59 return}60, public void setbalance (double balance) {62 this.balance = balance;63}64 65}
The above example is easy to understand, there is a bank card, which has a balance of 1000, the program simulates you and your wife at the same time at the teller machine to carry out money operation scene. Running this program multiple times may have several different combinations of output results. One of the possible outputs is:
1 to take the money successfully, the amount is: 700.02 is: 300.03 to take the money to succeed, the amount of cash to be removed: 700.04 is:-400.0
In other words, for a bank card with only 1000, you can take out 1400 altogether, which is obviously problematic.
After analysis, the problem lies in the uncertainty of execution in the Java multithreaded environment. The CPU may randomly switch between multiple threads in a ready state, so it is likely that when Thread1 executes to the//1 code, the condition is true, when the CPU switches to Thread2, executes the//1 code, finds that it is still true, Then executes the thread2, then switches to Thread1, then executes. At this point, the result will appear.
So, when it comes to thread safety, it means that access to shared resources in a multithreaded environment can cause inconsistencies in this shared resource. Therefore, to avoid thread-safety issues, you should avoid concurrent access to this shared resource in a multithreaded environment.
Two. Synchronization method
The method definition that accesses a shared resource is added with the Synchronized keyword adornment, making this method known as a synchronous method. This method can be simply understood to be locked, and its lock object is the object itself where the current method resides. In a multithreaded environment, when this method is executed, the synchronization lock is first acquired (and at most one thread is available at the same time), and the lock object is released only when the thread finishes executing the synchronization method, and the other threads are likely to get the synchronization lock, and so on ...
In the above example, the shared resource is the account object, and when you use the synchronization method, you can resolve the thread safety issue. Just add the Synshronized keyword before the run () method.
1 public synchronized void Run () {2 3 //.... 4 5}
Three. Synchronizing code blocks
As analyzed above, solving thread-safety problems simply limits the uncertainty of access to shared resources. When using the synchronous method, the whole method body becomes the synchronous execution state, which makes it possible for the synchronization scope to be too large, so that the code that needs synchronization can be solved by synchronizing the code block directly with another synchronization mode.
The format of the synchronization code block is:
1 synchronized (obj) {2 3 //... 4 5}
Where obj is the lock object, it is important to choose which object to use as a lock. In general, this shared resource object is selected as the lock object.
As in the example above, it is best to use the account object as the lock object. (Of course, the use of this is also possible, because the creation of threads using the runnable way, if it is directly inherited thread method of creating threads, using this object as a synchronous lock will actually not play any role, because it is a different object.) Therefore, you need to take extra care when choosing a sync lock ... )
Four. Lock Object Sync Lock
As we can see above, just because the choice of the synchronous lock object needs to be so careful, is there any simple solution? To facilitate the synchronization lock object and shared resources decoupling, but also a good solution to the problem of thread safety.
Using the Lock object synchronization lock is a convenient solution to this problem, and the only thing you need to be aware of is that the lock object needs to have a one-to-ones relationship with the resource object. Lock Object Sync Lock the general format is:
1 class X {2 3 //display defines the lock synchronization lock object, which has a one-to-one relationship to the shared resource 4 private final lock lock = new Reentrantlock (); 5 6 public void M () {7 //Locking 8 lock.lock (); 9// ... Code that requires thread-safe synchronization One by one //Release lock lock lock.unlock (); }15 16}
Five. Wait ()/notify ()/notifyall () thread communication
These three methods are mentioned in the blog "Java Summary series: Java.lang.Object", although these three methods are mostly used in multi-threading, but are actually local methods in the Object class. Therefore, in theory, any object objects can be the keynote of these three methods, in the actual multithreaded programming, only the synchronous lock object tune these three methods, to complete the thread communication between multithreading.
Wait (): Causes the current thread to wait and put it into a wait-blocking state. This thread is awakened until other threads call the Notify () or Notifyall () method of the synchronization lock object.
Notify (): Wakes a single thread waiting on this synchronization lock object, and if more than one thread waits on this synchronization lock object, any one of the threads will be selected for wake-up operation, and the thread that wakes up may be executed only if the thread discards the lock on the synchronization lock object.
Notifyall (): Wakes all threads waiting on this sync lock object, and only the thread that wakes up can be executed if the front thread discards the lock on the synchronization lock object.
1 package Com.qqyumidi; 2 3 public class ThreadTest {4 5 public static void main (string[] args) {6 account account = new Accou NT ("123456", 0); 7 8 Thread Drawmoneythread = new Drawmoneythread ("Take Money Thread", account, 700); 9 Thread depositemoneythread = new Depositemoneythread ("Savings thread", account, 700); Ten Drawmoneythread.start (); Depositemoneythread.start (); ------class Drawmoneythread extends Thread {. Amount Public Drawmoneythread (String threadname, account account, double amount) {threadname); 24 This.account = account; This.amount = amount; The public void Run () {(int i = 0; i < i++) {Account.draw (amount, i); +} (+}) Depositemoneythread extends Thread {The PNS private account account; Ivate double amount;Depositemoneythread (String threadname, account account, double amount) {4 super (threadname); 2 This.account = account; This.amount = amount; () {i++} (int i = 0; I <) {Account.deposite (Amou NT, i); * * * * * * * The class Account {Accountno private String; balance; 57 Identifies whether the account has a deposit of $ private Boolean flag = false; The public account () {Accountno} (String, double balance) {THIS.A Ccountno = Accountno; This.balance = balance; () (Getaccountno) () () () {Accountno return; No (String accountno) {this.accountno = Accountno; n} the public double GetBalance () {78 return balance; Setbalance (double balance) {82 This.balance = balance; 83} 84 85/** 86 * Save money * * * @param depositeamount * * * * synchronized void Deposite (double depositeamount, int i) {(flag) {93///account has already been saved in, at which point the current thread needs to wait for blocking 94 try {System.out.println (Thread.CurrentThread (). GetName () + "start to perform wait operation" + "--i=" + i); 96 Wait (); //1 98 System.out.println (Thread.CurrentThread (). GetName () + "Wait operation" + "--i=" + i); (Interruptedexception e) {e.printstacktrace (); 101}102} el SE {103//Start Saving 104 System.out.println (Thread.CurrentThread (). GetName () + "deposit:" + Depositeamount + "--i=" + i); Setbalance (balance + depositeamount); 106 flag = true;107 108//Wake it Up He thread 109 notifyall (); 111//2112 try {113 Thread.Sleep (interruptedexception e) {e.printstacktrace (); 116 }117 System.out.println (Thread.CurrentThread () getName () + "--Save--Execution complete" + "--i=" + i); 118 }119}120 121/**122 * Take money 123 * 124 * @param drawAmount125 */126 public synchronized void Draw (double drawamount, int i) {127 if (!flag) {128//The account has not yet been saved in, at which point the current thread needs to wait for blocking 129 try {13 0 System.out.println (Thread.CurrentThread (). GetName () + "start to perform wait operation" + "execute wait operation" + "--i=" + i); 131 Wait (); System.out.println (Thread.CurrentThread (). GetName () + "wait operation performed" + " "+"--i= "+ i); 133} catch (Interruptedexception e) {134 e.printstacktrace (); 135 }136} else {137//start taking Money 138 System.out.println (Thread.CurrentThread (). GetName () + "withdraw money: "+ Drawamount +"--i="+ i); 139 setbalance (GetBalance ()-drawamount); 141 flag = false;142 143//Wake Up other lines Cheng 144 notifyall (); 145 146 System.out.println (Thread.CurrentThread (). GetName () + "--take money--execution complete" + " --i= "+ i); 3147}148}149 150}
The example above demonstrates the use of Wait ()/notify ()/notifyall (). Some of the output results are:
1 Take the money thread starts to perform wait operation execution wait operation--i=0 2 savings Thread Deposit: 700.0--i=0 3 saving thread--saving-------------------i=0 4 The money-saving thread started to perform the wait operation--I=1 5 Take the money thread executed Wait operation performed wait operation--i=0 6 take money thread to withdraw money: 700.0--I=1 7 Take money thread--take money--execute--I=1 8 Get money thread start to perform wait operation execution wait operation--i=2 9 saving thread executed WA IT operations--i=110 savings Thread Deposit: 700.0--i=211 saving thread--saving------the execution is done--i=212 take the money thread executed wait operation--i=213 take money thread to withdraw money: 700.0--i=314 Fetch Money thread--take money--execute--i=315 take the money thread starts to perform wait operation execution wait operation--i=416 deposit thread Deposits: 700.0--i=317 saving money thread--saving--execution complete--i=318 The deposit thread starts to execute Wait operation--the i=419 thread executed the wait operation--the i=420 took the money thread to withdraw money: 700.0--i=521 Take the money thread--Take the money--execute--the i=522 take the money thread started to perform the wait operation executed WA IT operations--i=623 saving thread has performed wait operation--i=424 saving thread deposit: 700.0--i=525 savings thread--saving--execution complete--i=526 the money-saving thread started to perform the wait operation--the i=627 fetch thread executed the The wait operation performed a wait operation--the i=628 took the money thread to withdraw money: 700.0--i=729 Take the money thread--take money--execute--i=730 take the money thread started to do wait operation execution wait operation--i=831 save a thread executed WA IT operations--i=632 savings Thread Deposit: 700.0--i=7
Thus, we need to pay attention to the following points:
After the 1.wait () method executes, the current thread immediately enters the wait-blocking state, after which the code does not execute;
The 2.notify ()/notifyall () method wakes up (any one of the-notify ()/All-notifyall ()) thread objects on this synchronization lock object, but at this point the synchronization lock object is not released, that is, if the Notify ()/ Notifyall () is followed by code that will continue, knowing that the current thread has finished executing before releasing the synchronization lock object;
3.notify ()/notifyall () after execution, if the right side of the sleep () method, it will cause the current thread into the blocking state, but the synchronization object lock is not released, and still keep, then after a certain time will continue to execute this thread, followed by 2;
4.wait ()/notify ()/nitifyall () the completion of communication or collaboration between threads is based on different object locks, so if a different synchronization object lock will lose meaning, at the same time, the synchronization object lock is best to maintain a one by one correspondence with the shared resource object;
5. When the wait thread wakes up and executes, it continues after the wait () method code that was last executed.
Of course, the above example is relatively simple, just for the simple example of the use of the Wait ()/notify ()/noitifyall () method, but it is essentially a simple producer-consumer model.
[Reprint] Java Multithreading Summary (iii)