1 The difference between synchronized, Lock and volatile thread locks
1.1 The difference between synchronized and volatile
usage:
- The volatile keyword solves the problem of visibility of variables between multiple threads;
- The synchronized keyword solves the synchronization of access to shared resources between multiple threads;
- When multiple threads access volatile, the program will not block; when accessing synchronized modified methods or code blocks, blocking will occur;
- volatile can guarantee the visibility of variables between multiple threads, but cannot guarantee atomicity; synchronized can guarantee the atomicity of data operations and can also indirectly guarantee the visibility of data, and will separate the data in private memory and public memory in the thread. Synchronize.
For example, when we use a credit card for consumption, if the bank freezes the card during consumption, the deduction should be rejected.
At this time, all threads need to be able to see the change in the card status, otherwise it will cause user losses.
To make this status visible to any thread, you need to usevolatile
to modify the variable.
Deductions are easier to understand. If the debit actions of the account are not locked, the same amount of money in the account can be consumed repeatedly, which will cause losses to the bank. After the lock is added, all deductions will be carried out serially here , and each consumption will be deducted one by one to avoid account overdraft or repeated payments.
scenes to be used:
- The volatile keyword can only be used to modify variables;
- The synchronized keyword can modify methods and code blocks.
1.2 The difference between synchronized and Lock
accomplish
Lock is an interface, synchronized
but a keyword in Java, implemented by the built-in language.
Exception handling mechanism
synchronized will automatically release the lock occupied by the thread when an exception occurs, so it will not cause deadlock;
When an exception occurs, if Lock does not actively release the lock through the unlock() method, it is likely to cause a deadlock. Therefore, when using Lock, you need to add a statement to manually release the lock in the finally block.
synchronized{ 语句块; } Lock lock = new ReentrantLock() lock.lock(); lock.unLock();
lock() and unlock() must exist in pairs.
efficiency
Lock can improve the efficiency of read operations by multiple threads (read-write lock).
2 Thread read-write separation mechanism
isReadWriteLock
a read-write lock:
- A pair of related locks "read lock" and "write lock" are maintained, one for read operations and the other for write operations.
- Read lock is used for read-only operations. It is a shared lock and can be acquired by multiple threads at the same time.
- The write lock is used for write operations. It is an exclusive lock. The write lock can only be acquired by one thread lock.
- Read locks and write locks cannot exist at the same time. Read/read operations can be performed at the same time, but read/write and write/write operations cannot be performed at the same time.
2.1 Create account class
public class MyCount { private String id;//Account private int cash;//Account balance public MyCount(String id, int cash) { this.id = id; this.cash = cash; } public String getId() { return id ; } public void setId(String id) { this.id = id; } //Read operation public int getCash() { System.out.println(Thread.currentThread().getName() + " getcash, cash=" + cash); return cash; } //Write operation public void setCash(int cash) { System.out.println(Thread.currentThread().getName() + " setcash, cash=" + cash); this.cash = cash; } }
2.2 Create user information class
A read-write lock is declared in the user information class,
and create a read lock in the read method,
Create a write lock in the write method,
All locks need to be closed manually after use.
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class User { private String name; private MyCount myCount; //声明读写锁 private ReadWriteLock readWriteLock; public User(String name, MyCount myCount) { this.name = name; this.myCount = myCount; this.readWriteLock = new ReentrantReadWriteLock(); } //查询余额 public void getCash(){ new Thread(){ @Override public void run() { //创建读取锁 readWriteLock.readLock().lock(); try { System.out.println(Thread.currentThread().getName() + " getCash start"); myCount.getCash(); Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + " getCash end"); } catch (InterruptedException e) { e.printStackTrace(); } finally { //手动关闭锁 readWriteLock.readLock().unlock(); } } }.start(); } //设置余额 public void setCash(final int cash){ new Thread(){ @Override public void run() { //Create a write lock readWriteLock.writeLock().lock(); try { System.out.println(Thread.currentThread().getName() + " setCash start"); myCount.setCash(cash); Thread.sleep (1000); System.out.println(Thread.currentThread().getName() + " setCash end"); } catch (InterruptedException e) { e.printStackTrace(); } finally { //Close the lock manually readWriteLock.writeLock ().unlock(); } } }.start(); } }
2.3 Create test class
Create users and accounts in the test class, and use multi-threading to read and write account information.
public class Test { public static void main(String[] args) { //Create account MyCount myCount = new MyCount("abcd12", 5000); //Create user and specify account User user = new User("Xiao Zhang" , myCount); for (int i = 0; i < 3; i++) { user.getCash(); user.setCash((i + 1) * 1000); } } }
2.4 Output results
Thread-0 getCash start
Thread-0 getcash, cash=5000
Thread-2 getCash start
Thread-2 getcash, cash=5000
Thread-2 getCash end
Thread-0 getCash end
Thread-1 setCash start
Thread-1 setcash, cash=1000
Thread-1 setCash end
Thread-4 getCash start
Thread-4 getcash, cash=1000
Thread-4 getCash end
Thread-5 setCash start
Thread-5 setcash, cash=3000
Thread-5 setCash end
Thread-3 setCash start
Thread-3 setcash, cash=2000
Thread-3 setCash end
In the output results, you can see:
The read operation getCash is executed in Thread-0, but before it is completed, Thread-2 also enters the read operation at the same time, and they are executed in parallel ;
For the write operation setCash, all threads are executed from start to end, and no other threads enter in the middle. It is an exclusive execution .