Why synchronization is required
Java allows multi-thread concurrency control. When multiple threads operate a shared Resource variables (such as addition, deletion, modification and query of data) will lead to inaccurate data and conflicts with each other. Therefore, a synchronization lock is added to avoid being called by other threads before the thread completes the operation, thereby ensuring that the thread Uniqueness and accuracy of variables.
1. Example
For example, if a bank account is operated by two threads at the same time, one takes 100 yuan and the other deposits 100 yuan. Assume that the account originally has 0 blocks. If the withdrawal thread and the deposit thread occur at the same time, what will happen? The withdrawal was unsuccessful and the account balance is 100. The withdrawal was successful and the account balance is 0. But which balance corresponds to which? It's hard to tell clearly, so the problem of multi-thread synchronization arises.
2. Situation without synchronization
For example, if a bank account is operated by two threads at the same time, one takes 100 yuan and the other deposits 100 yuan. . Assume that the account originally has 0 blocks. If the withdrawal thread and the deposit thread occur at the same time, what will happen? If the money withdrawal is unsuccessful, the account balance is 100. If the money withdrawal is successful, the account balance is 0. But which balance corresponds to which? It's hard to tell clearly, so the problem of multi-thread synchronization arises.
public class Bank { private int count =0;//賬戶余額 //存錢(qián) public void addMoney(int money){ count +=money; System.out.println(System.currentTimeMillis()+"存進(jìn):"+money); } //取錢(qián) public void subMoney(int money){ if(count-money < 0){ System.out.println("余額不足"); return; } count -=money; System.out.println(+System.currentTimeMillis()+"取出:"+money); } //查詢 public void lookMoney(){ System.out.println("賬戶余額:"+count); } }
package threadTest; public class SyncThreadTest { public static void main(String args[]){ final Bank bank=new Bank(); Thread tadd=new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub while(true){ try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } bank.addMoney(100); bank.lookMoney(); System.out.println("\n"); } } }); Thread tsub = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub while(true){ bank.subMoney(100); bank.lookMoney(); System.out.println("\n"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }); tsub.start(); tadd.start(); } }
Run result:
1502542307917取出:100 賬號(hào)余額:100 1502542308917存進(jìn):100 1502542308917取出:100 賬號(hào)余額:0 賬號(hào)余額:0 1502542309917存進(jìn):100 賬號(hào)余額:0 1502542309917取出:100 賬號(hào)余額:0
A non-thread safety problem occurs at this time, because two threads access an unsynchronized method at the same time. If these two threads operate instances in the business object at the same time, variables, non-thread safety issues may occur.
Solution: Just add the synchronized keyword in front of public void run().
3. Synchronization method
synchronized keyword modification method
There is a synchronized keyword modification method. Since every object in Java has a built-in lock, when a method is modified with this keyword, the built-in lock will protect the entire method. Before calling this method, you need to obtain the built-in lock, otherwise it will be blocked.
Code such as:
public synchronized void save(){}
Note: The synchronized keyword can also modify static methods. If the static method is called at this time, the entire class will be locked.
public class Bank { private int count =0;//賬戶余額 //存錢(qián) public synchronized void addMoney(int money){ count +=money; System.out.println(System.currentTimeMillis()+"存進(jìn):"+money); } //取錢(qián) public synchronized void subMoney(int money){ if(count-money < 0){ System.out.println("余額不足"); return; } count -=money; System.out.println(+System.currentTimeMillis()+"取出:"+money); } //查詢 public void lookMoney(){ System.out.println("賬戶余額:"+count); } }
Run result:
余額不足 賬號(hào)余額:0 1502543814934存進(jìn):100 賬號(hào)余額:100 1502543815934存進(jìn):100 賬號(hào)余額:200 1502543815934取出:100 賬號(hào)余額:100
Thread synchronization is achieved in this way
Synchronization code block
That is, modified by the synchronized keyword block of statements.
The statement block modified by this keyword will automatically be added with a built-in lock to achieve synchronization
Code such as:
synchronized(object){ }
Note: Synchronization is a high-cost method operation, so synchronized content should be minimized.
Usually there is no need to synchronize the entire method, just use synchronized code blocks to synchronize key codes.
public class Bank { private int count =0;//賬戶余額 //存錢(qián) public void addMoney(int money){ synchronized (this) { count +=money; } System.out.println(System.currentTimeMillis()+"存進(jìn):"+money); } //取錢(qián) public void subMoney(int money){ synchronized (this) { if(count-money < 0){ System.out.println("余額不足"); return; } count -=money; } System.out.println(+System.currentTimeMillis()+"取出:"+money); } //查詢 public void lookMoney(){ System.out.println("賬戶余額:"+count); } }
The running results are as follows:
余額不足 賬戶余額:0 余額不足 賬戶余額:100 1502544966411存進(jìn):100 賬戶余額:100 1502544967411存進(jìn):100 賬戶余額:100 1502544967411取出:100 賬戶余額:100 1502544968422取出:100
This also achieves thread synchronization, and the operating efficiency is higher than method synchronization. Synchronization is a high-cost operation, so synchronization should be minimized. Content. Usually there is no need to synchronize the entire method, just use synchronized code blocks to synchronize key code.
Use special domain variables (volatile) to achieve thread synchronization
a. The volatile keyword provides a lock-free mechanism for access to member variables;
b. Using volatile to modify member variables is equivalent to telling the virtual machine that the field may be updated by other threads;
c. Therefore, each time the member variable is used, it must be recalculated instead of using the value in the register. Value;
d.volatile does not provide any atomic operations, nor can it be used to modify final type variables.
Bank.java code is as follows:
package com.thread.demo; /** * Created by HJS on 2017/8/12. */ public class Bank { private volatile int count =0;//賬戶余額 //存錢(qián) public void addMoney(int money){ synchronized (this) { count +=money; } System.out.println(System.currentTimeMillis()+"存進(jìn):"+money); } //取錢(qián) public void subMoney(int money){ synchronized (this) { if(count-money < 0){ System.out.println("余額不足"); return; } count -=money; } System.out.println(+System.currentTimeMillis()+"取出:"+money); } //查詢 public void lookMoney(){ System.out.println("賬戶余額:"+count); } }
Running result:
余額不足 賬戶余額:0 余額不足 賬戶余額:100 1502546287474存進(jìn):100 賬戶余額:100 1502546288474存進(jìn):100 1502546288474取出:100 賬戶余額:100
At this time, the order is messed up again, indicating that there is another synchronization problem, because volatile cannot guarantee atomic operations. Caused by this, volatile cannot replace synchronized. In addition, volatile will prevent the compiler from optimizing the code, so if you can't use it, don't apply it. Its principle is that every time a thread wants to access a volatile-modified variable, it reads it from the memory instead of reading it from the cache, so the variable value accessed by each thread is the same. This ensures synchronization.
Using reentrancy locks to achieve thread synchronization
A new java.util.concurrent package has been added in JavaSE5.0 to support synchronization. The ReentrantLock class is a reentrant, mutually exclusive lock that implements the Lock interface. It has the same basic behavior and semantics as using synchronized methods and blocks, and extends its capabilities.
Commonly used methods of the ReenreantLock class are:
ReentrantLock(): Create a ReentrantLock instance
lock(): Obtain the lock
unlock(): Release Lock
Note: ReentrantLock() also has a construction method that can create a fair lock, but it is not recommended because it can greatly reduce the running efficiency of the program.
Bank.java code is modified as follows:
public class Bank { private int count = 0;// 賬戶余額 //需要聲明這個(gè)鎖 private Lock lock = new ReentrantLock(); // 存錢(qián) public void addMoney(int money) { lock.lock();//上鎖 try{ count += money; System.out.println(System.currentTimeMillis() + "存進(jìn):" + money); }finally{ lock.unlock();//解鎖 } } // 取錢(qián) public void subMoney(int money) { lock.lock(); try{ if (count - money < 0) { System.out.println("余額不足"); return; } count -= money; System.out.println(+System.currentTimeMillis() + "取出:" + money); }finally{ lock.unlock(); } } // 查詢 public void lookMoney() { System.out.println("賬戶余額:" + count); } }
Running result:
余額不足 賬戶余額:0 1502547439892存進(jìn):100 賬戶余額:100 1502547440892存進(jìn):100 賬戶余額:200 1502547440892取出:100 賬戶余額:100
Note: Regarding the selection of Lock object and synchronized keyword:
a. It is best to use neither of them, and use a mechanism provided by the java.util.concurrent package to help users handle all lock-related code.
b.如果synchronized關(guān)鍵字能滿足用戶的需求,就用synchronized,因?yàn)樗芎?jiǎn)化代碼。
c.如果需要更高級(jí)的功能,就用ReentrantLock類(lèi),此時(shí)要注意及時(shí)釋放鎖,否則會(huì)出現(xiàn)死鎖,通常在finally代碼釋放鎖 。
使用局部變量實(shí)現(xiàn)線程同步
代碼如下:
public class Bank { private static ThreadLocal<Integer> count = new ThreadLocal<Integer>(){ @Override protected Integer initialValue() { // TODO Auto-generated method stub return 0; } }; // 存錢(qián) public void addMoney(int money) { count.set(count.get()+money); System.out.println(System.currentTimeMillis() + "存進(jìn):" + money); } // 取錢(qián) public void subMoney(int money) { if (count.get() - money < 0) { System.out.println("余額不足"); return; } count.set(count.get()- money); System.out.println(+System.currentTimeMillis() + "取出:" + money); } // 查詢 public void lookMoney() { System.out.println("賬戶余額:" + count.get()); } }
運(yùn)行結(jié)果如下:
復(fù)制代碼 余額不足 賬戶余額:0 余額不足 1502547748383存進(jìn):100 賬戶余額:100 賬戶余額:0 余額不足 賬戶余額:0 1502547749383存進(jìn):100 賬戶余額:200
看了運(yùn)行效果,一開(kāi)始一頭霧水,怎么只讓存,不讓取啊?看看ThreadLocal的原理:
如果使用ThreadLocal管理變量,則每一個(gè)使用該變量的線程都獲得該變量的副本,副本之間相互獨(dú)立,這樣每一個(gè)線程都可以隨意修改自己的變量副本,而不會(huì)對(duì)其他線程產(chǎn)生影響?,F(xiàn)在明白了吧,原來(lái)每個(gè)線程運(yùn)行的都是一個(gè)副本,也就是說(shuō)存錢(qián)和取錢(qián)是兩個(gè)賬戶,知識(shí)名字相同而已。所以就會(huì)發(fā)生上面的效果。
ThreadLocal 類(lèi)的常用方法
ThreadLocal() : 創(chuàng)建一個(gè)線程本地變量? ? ?
get() : 返回此線程局部變量的當(dāng)前線程副本中的值? ? ?
initialValue() : 返回此線程局部變量的當(dāng)前線程的"初始值"? ? ?
set(T value) : 將此線程局部變量的當(dāng)前線程副本中的值設(shè)置為value
注:ThreadLocal與同步機(jī)制
a.ThreadLocal與同步機(jī)制都是為了解決多線程中相同變量的訪問(wèn)沖突問(wèn)題。?
b.前者采用以"空間換時(shí)間"的方法,后者采用以"時(shí)間換空間"的方式。
php中文網(wǎng),大量的免費(fèi)Java入門(mén)教程,歡迎在線學(xué)習(xí)!
The above is the detailed content of How to synchronize Java. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

The settings.json file is located in the user-level or workspace-level path and is used to customize VSCode settings. 1. User-level path: Windows is C:\Users\\AppData\Roaming\Code\User\settings.json, macOS is /Users//Library/ApplicationSupport/Code/User/settings.json, Linux is /home//.config/Code/User/settings.json; 2. Workspace-level path: .vscode/settings in the project root directory

To correctly handle JDBC transactions, you must first turn off the automatic commit mode, then perform multiple operations, and finally commit or rollback according to the results; 1. Call conn.setAutoCommit(false) to start the transaction; 2. Execute multiple SQL operations, such as INSERT and UPDATE; 3. Call conn.commit() if all operations are successful, and call conn.rollback() if an exception occurs to ensure data consistency; at the same time, try-with-resources should be used to manage resources, properly handle exceptions and close connections to avoid connection leakage; in addition, it is recommended to use connection pools and set save points to achieve partial rollback, and keep transactions as short as possible to improve performance.

DependencyInjection(DI)isadesignpatternwhereobjectsreceivedependenciesexternally,promotingloosecouplingandeasiertestingthroughconstructor,setter,orfieldinjection.2.SpringFrameworkusesannotationslike@Component,@Service,and@AutowiredwithJava-basedconfi

Use classes in the java.time package to replace the old Date and Calendar classes; 2. Get the current date and time through LocalDate, LocalDateTime and LocalTime; 3. Create a specific date and time using the of() method; 4. Use the plus/minus method to immutably increase and decrease the time; 5. Use ZonedDateTime and ZoneId to process the time zone; 6. Format and parse date strings through DateTimeFormatter; 7. Use Instant to be compatible with the old date types when necessary; date processing in modern Java should give priority to using java.timeAPI, which provides clear, immutable and linear

TheJVMenablesJava’s"writeonce,runanywhere"capabilitybyexecutingbytecodethroughfourmaincomponents:1.TheClassLoaderSubsystemloads,links,andinitializes.classfilesusingbootstrap,extension,andapplicationclassloaders,ensuringsecureandlazyclassloa

ChromecanopenlocalfileslikeHTMLandPDFsbyusing"Openfile"ordraggingthemintothebrowser;ensuretheaddressstartswithfile:///;2.SecurityrestrictionsblockAJAX,localStorage,andcross-folderaccessonfile://;usealocalserverlikepython-mhttp.server8000tor

Pre-formanceTartuptimeMoryusage, Quarkusandmicronautleadduetocompile-Timeprocessingandgraalvsupport, Withquarkusoftenperforminglightbetterine ServerLess scenarios.2.Thyvelopecosyste,

Networkportsandfirewallsworktogethertoenablecommunicationwhileensuringsecurity.1.Networkportsarevirtualendpointsnumbered0–65535,withwell-knownportslike80(HTTP),443(HTTPS),22(SSH),and25(SMTP)identifyingspecificservices.2.PortsoperateoverTCP(reliable,c
