Java learning notes-five methods of multi-thread synchronization, java learning notes
I. Introduction
A few days ago, the interview was abused by the master and a lot of basic knowledge had to be taken up again. If you don't talk much about it, go to the topic.
Ii. Why thread synchronization?
Because when we have multiple threads that want to access a variable or object at the same time, if there are both read and write operations in these threads, it will lead to confusion of the variable value or object status, this causes program exceptions. For example, if a bank account is operated by two threads at the same time, one takes 100 yuan and the other saves 100 yuan. Assume that there are 0 accounts. What will happen if both the money withdrawal thread and the deposit thread occur? Fail to get the money. The account balance is 100. The money is successfully obtained, and the account balance is 0. Which one is it? It is hard to say clearly. Therefore, multithreading synchronization is to solve this problem.
3. Code for different steps
Bank. java
- PackagethreadTest;
-
- /**
- * @ Authorww
- *
- */
- PublicclassBank {
-
- Privateintcount = 0; // account balance
-
- // Save money
- PublicvoidaddMoney (intmoney ){
- Count + = money;
- System. out. println (System. currentTimeMillis () + "saved in:" + money );
- }
-
- // Get the money
- PublicvoidsubMoney (intmoney ){
- If (count-money <0 ){
- System. out. println ("insufficient balance ");
- Return;
- }
- Count-= money;
- System. out. println (+ System. currentTimeMillis () + "retrieve:" + money );
- }
-
- // Query
- PublicvoidlookMoney (){
- System. out. println ("account balance:" + count );
- }
- }
SyncThreadTest. java
- PackagethreadTest;
-
-
- PublicclassSyncThreadTest {
-
- Publicstaticvoidmain (Stringargs []) {
- FinalBankbank = newBank ();
-
- Threadtadd = newThread (newRunnable (){
-
- @ Override
- Publicvoidrun (){
- // TODOAuto-generatedmethodstub
- While (true ){
- Try {
- Thread. sleep (1000 );
- } Catch (InterruptedExceptione ){
- // TODOAuto-generatedcatchblock
- E. printStackTrace ();
- }
- Bank. addMoney (100 );
- Bank. lookMoney ();
- System. out. println ("n ");
-
- }
- }
- });
-
- Threadtsub = newThread (newRunnable (){
-
- @ Override
- Publicvoidrun (){
- // TODOAuto-generatedmethodstub
- While (true ){
- Bank. subcurrency (100 );
- Bank. lookMoney ();
- System. out. println ("n ");
- Try {
- Thread. sleep (1000 );
- } Catch (InterruptedExceptione ){
- // TODOAuto-generatedcatchblock
- E. printStackTrace ();
- }
- }
- }
- });
- Tsub. start ();
-
- Tadd. start ();
- }
-
-
-
- }
The code is very simple. I will not explain it. What is the running result? If some of them are intercepted, is it messy.
- Insufficient balance
- Account Balance: 0
-
-
- Insufficient balance
- Balance: 100
-
-
- 1441790503354: 100
- Balance: 100
-
-
- 1441790504354: 100
- Balance: 100
-
-
- 1441790504354 fetch: 100
- Balance: 100
-
-
- 1441790505355: 100
- Balance: 100
-
-
- 1441790505355 fetch: 100
- Balance: 100
4. Use the synchronization code (1) synchronization method:
There is also a method for modifying the synchronized keyword. Because every object in java has a built-in lock, when this keyword is used to modify the method, the built-in lock will protect the entire method. You must obtain the built-in lock before calling this method. Otherwise, the lock is blocked.
Modified Bank. java
- PackagethreadTest;
-
- /**
- * @ Authorww
- *
- */
- PublicclassBank {
-
- Privateintcount = 0; // account balance
-
- // Save money
- PublicsynchronizedvoidaddMoney (intmoney ){
- Count + = money;
- System. out. println (System. currentTimeMillis () + "saved in:" + money );
- }
-
- // Get the money
- PublicsynchronizedvoidsubMoney (intmoney ){
- If (count-money <0 ){
- System. out. println ("insufficient balance ");
- Return;
- }
- Count-= money;
- System. out. println (+ System. currentTimeMillis () + "retrieve:" + money );
- }
-
- // Query
- PublicvoidlookMoney (){
- System. out. println ("account balance:" + count );
- }
- }
Let's look at the running result:
- Insufficient balance
- Account Balance: 0
-
-
- Insufficient balance
- Account Balance: 0
-
-
- 1441790837380: 100
- Balance: 100
-
-
- 1441790838380 fetch: 100
- Account Balance: 0
- 1441790838380: 100
- Balance: 100
-
-
-
-
- 1441790839381 fetch: 100
- Account Balance: 0
I can understand it in an instant.
Note: The synchronized keyword can also modify the static method. If you call this static method, the entire class will be locked.
(2) Synchronous Code Block
There are statement blocks modified by the synchronized keyword. The statement block modified by this keyword is automatically added with a built-in lock to achieve synchronization.
The Bank. java code is as follows:
- PackagethreadTest;
-
- /**
- * @ Authorww
- *
- */
- PublicclassBank {
-
- Privateintcount = 0; // account balance
-
- // Save money
- PublicvoidaddMoney (intmoney ){
-
- Synchronized (this ){
- Count + = money;
- }
- System. out. println (System. currentTimeMillis () + "saved in:" + money );
- }
-
- // Get the money
- PublicvoidsubMoney (intmoney ){
-
- Synchronized (this ){
- If (count-money <0 ){
- System. out. println ("insufficient balance ");
- Return;
- }
- Count-= money;
- }
- System. out. println (+ System. currentTimeMillis () + "retrieve:" + money );
- }
-
- // Query
- PublicvoidlookMoney (){
- System. out. println ("account balance:" + count );
- }
- }
The running result is as follows:
- Insufficient balance
- Account Balance: 0
-
-
- 1441791806699: 100
- Balance: 100
-
-
- 1441791806700 fetch: 100
- Account Balance: 0
-
-
- 1441791807699: 100
- Balance: 100
The effect is similar to method 1.
Note: synchronization is a highly open operation, so you should minimize the amount of synchronization content. Generally, there is no need to synchronize the entire method. Use the synchronized code block to synchronize key code.
(3) use special domain variables (volatile) for Thread Synchronization
A. The volatile keyword provides a lock-free mechanism for access to domain variables.
B. Modifying the domain using volatile is equivalent to telling the virtual machine that the domain may be updated by other threads.
C. Therefore, each time you use this field, you need to recalculate it instead of using the value in the register.
D. volatile does not provide any atomic operations, nor can it be used to modify final-type variables.
The Bank. java code is as follows:
- PackagethreadTest;
-
- /**
- * @ Authorww
- *
- */
- PublicclassBank {
-
- Privatevolatileintcount = 0; // account balance
-
- // Save money
- PublicvoidaddMoney (intmoney ){
-
- Count + = money;
- System. out. println (System. currentTimeMillis () + "saved in:" + money );
- }
-
- // Get the money
- PublicvoidsubMoney (intmoney ){
-
- If (count-money <0 ){
- System. out. println ("insufficient balance ");
- Return;
- }
- Count-= money;
- System. out. println (+ System. currentTimeMillis () + "retrieve:" + money );
- }
-
- // Query
- PublicvoidlookMoney (){
- System. out. println ("account balance:" + count );
- }
- }
What is the running effect?
- Insufficient balance
- Account Balance: 0
-
-
- Insufficient balance
- Balance: 100
-
-
- 1441792010959: 100
- Balance: 100
-
-
- 1441792011960 fetch: 100
- Account Balance: 0
-
-
- 1441792011961: 100
- Balance: 100
Are you confused. Why? Because volatile cannot guarantee atomic operations, volatile cannot replace synchronized. In addition, volatile will organize the compiler to optimize the code, so it is not applicable if it is not used. The principle is that every time a thread wants to access a variable modified by volatile, it reads data from the memory instead of the memory cache. Therefore, the variable values accessed by each thread are the same. This ensures synchronization.
(4) use the re-entry lock for Thread Synchronization
Added a java. util. concurrent package in JavaSE5.0 to support synchronization. The ReentrantLock class is a reentrant and mutex Lock that implements the Lock interface. It has the same basic behavior and semantics as using the synchronized Method and fast, and extends its capabilities.
Common ReenreantLock methods include:
ReentrantLock (): Creates a ReentrantLock instance.
Lock (): Get the lock
Unlock (): Release the lock
Note: ReentrantLock () also has a constructor that can create a fair lock. However, it is not recommended because it can greatly reduce the program running efficiency.
The Bank. java code is modified as follows:
- PackagethreadTest;
-
- Importjava. util. concurrent. locks. Lock;
- Importjava. util. concurrent. locks. ReentrantLock;
-
- /**
- * @ Authorww
- *
- */
- PublicclassBank {
-
- Privateintcount = 0; // account balance
-
- // The lock needs to be declared
- PrivateLocklock = newReentrantLock ();
-
- // Save money
- PublicvoidaddMoney (intmoney ){
- Lock. lock (); // lock
- Try {
- Count + = money;
- System. out. println (System. currentTimeMillis () + "saved in:" + money );
-
- } Finally {
- Lock. unlock (); // unlock
- }
- }
-
- // Get the money
- PublicvoidsubMoney (intmoney ){
- Lock. lock ();
- Try {
-
- If (count-money <0 ){
- System. out. println ("insufficient balance ");
- Return;
- }
- Count-= money;
- System. out. println (+ System. currentTimeMillis () + "retrieve:" + money );
- } Finally {
- Lock. unlock ();
- }
- }
-
- // Query
- PublicvoidlookMoney (){
- System. out. println ("account balance:" + count );
- }
- }
How is the running effect?
- Insufficient balance
- Account Balance: 0
-
-
- Insufficient balance
- Account Balance: 0
-
-
- 1441792891934: 100
- Balance: 100
-
-
- 1441792892935: 100
- Balance: 200
-
-
- 1441792892954 fetch: 100
- Balance: 100
The effect is similar to the previous two methods.
If the synchronized keyword can meet your needs, use synchronized because it simplifies code. If you need more advanced functions, use the ReentrantLock class. Pay attention to releasing the lock in time. Otherwise, a deadlock occurs. Usually, the lock is released in finally code.
(5) use local variables for Thread Synchronization
The Bank. java code is as follows:
- PackagethreadTest;
-
-
- /**
- * @ Authorww
- *
- */
- PublicclassBank {
-
- PrivatestaticThreadLocal <Integer> count = newThreadLocal <Integer> (){
-
- @ Override
- ProtectedIntegerinitialValue (){
- // TODOAuto-generatedmethodstub
- Return0;
- }
-
- };
-
-
- // Save money
- PublicvoidaddMoney (intmoney ){
- Count. set (count. get () + money );
- System. out. println (System. currentTimeMillis () + "saved in:" + money );
-
- }
-
- // Get the money
- PublicvoidsubMoney (intmoney ){
- If (count. get ()-money <0 ){
- System. out. println ("insufficient balance ");
- Return;
- }
- Count. set (count. get ()-money );
- System. out. println (+ System. currentTimeMillis () + "retrieve:" + money );
- }
-
- // Query
- PublicvoidlookMoney (){
- System. out. println ("account balance:" + count. get ());
- }
- }
Running effect:
- Insufficient balance
- Account Balance: 0
-
-
- Insufficient balance
- Account Balance: 0
-
-
- 1441794247939: 100
- Balance: 100
-
-
- Insufficient balance
- 1441794248940: 100
- Account Balance: 0
-
-
- Balance: 200
-
-
- Insufficient balance
- Account Balance: 0
-
-
- 1441794249941: 100
- Balance: 300
After reading the running effect, I was confused at the beginning. How can I just save it? Let's take a look at the principle of ThreadLocal:
If ThreadLocal is used to manage a variable, each thread that uses the variable obtains a copy of the variable. The copies are independent of each other, so that each thread can modify its own copy of the variable at will, it does not affect other threads. Now, I understand that each thread runs a copy. That is to say, there are two accounts for saving and obtaining money, and the same knowledge name is used. So the above effect will occur.
ThreadLocal and synchronization mechanism
A. The ThreadLocal and synchronization mechanisms are designed to solve the access conflicts of the same variables in multiple threads.
B. The former adopts the "space for Time" method, and the latter adopts the "Time for space" method.
I understand it now. Each has its own advantages and disadvantages and has its own applicable scenarios. Manual, eat now.
Q: customized IT education platform, one-to-one service, Q & A. Official Website for developing programming social headlines: www.wenaaa.com
QQ Group 290551701 has gathered many Internet elites, Technical Directors, architects, and project managers! Open-source technology research, welcome to the industry, Daniel and beginners interested in IT industry personnel!