Home >Java >javaTutorial >What is a lock in Java? Detailed introduction to locks in Java
The content of this article is about what is the lock in Java? The detailed introduction of locks in Java has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.
1. Introduction
Locking is implemented in JAVA through the Synchronized keyword and Related classes under the java.util.concurrent package.
Related API provided by Java for implementing locking:
Lock provides a wider range of locking operations than using Synchronized synchronization methods and synchronization statement blocks.
2.java.util.concurrent package
Lock interface
//试图获取锁. void lock() //如果当前线程未被中断,则获取锁. void lockInterruptibly() //返回绑定到此 Lock 实例的新 Condition 实例. Condition newCondition() //仅在调用时锁为空闲状态才获取该锁. boolean tryLock() //如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁. boolean tryLock(long time, TimeUnit unit) //试图释放锁. void unlock()
ReentranLock class
Construction method
//创建一个 ReentrantLock 的实例. ReentrantLock() //创建一个具有给定公平策略的 ReentrantLock实例. ReentrantLock(boolean fair)
Fair lock: Multi-threads acquire locks in the order in which they apply for locks.
Unfair lock: Multi-threads do not acquire locks in the order in which they apply for locks, that is, the thread that applies for the lock first may not necessarily be the first to acquire the lock.
Common method summary
//试图获取锁. void lock() //如果当前线程未被中断,则获取锁.void lockInterruptibly() //仅在调用时锁未被另一个线程保持的情况下,才获取该锁.boolean tryLock() //如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁. boolean tryLock(long timeout, TimeUnit unit) //试图释放此锁. void unlock() //返回用来与此 Lock 实例一起使用的 Condition 实例.Condition newCondition() //如果此锁的公平设置为 true,则返回 true.boolean isFair() //返回正等待获取此锁的线程估计数.int getQueueLength() //返回等待与此锁相关的给定条件的线程估计数.int getWaitQueueLength(Condition condition) //返回标识此锁及其锁定状态的字符串.String toString()
Condition interface
//使当前线程在接收到信号前或被中断前一直保持等待状态. void await() //使当前线程在接收到信号前或被中断前或达到指定时间前一直保持等待状态(TimeUnit为时间单位). boolean await(long time, TimeUnit unit) //使当前线程在接收到信号前或被中断前或达到指定时间前一直保持等待状态(单位为毫秒). long awaitNanos(long nanosTimeout) //使当前线程在接收到信号前或被中断前或达到最后日期期限前一直保持等待状态. boolean awaitUntil(Date deadline) //唤醒一个在该Condition实例等待的线程. void signal() //唤醒所有在该Condition实例等待的线程. void signalAll()
A Condition instance will be bound to a Lock instance as the condition control of the Lock instance.
Before calling the methods declared by the Condition interface, you need to obtain the lock related to this Condition first.
After the methods await(), await(long time, TimeUnit unit), awaitNanos(long nanosTimeout), awaitUntil(Date deadline) are called, this will Condition-related locks will be released atomically.
After the signal() and signalAll() methods are called, the awakened thread needs to reacquire the lock before returning from the await() method.
Usage example:
/** * @Auther: ZHUANGHAOTANG * @Date: 2018/9/26 17:36 * @Description: */ public class TestReentranLock implements Runnable{ /** * 可重入锁 */ private ReentrantLock reentrantLock = new ReentrantLock(true); /** * 锁条件 */ private Condition condition = reentrantLock.newCondition(); /** * 业务处理 */ public void service(){ String threadName = Thread.currentThread().getName(); System.out.println(threadName+":尝试获取锁"); reentrantLock.lock(); System.out.println(threadName+":获取锁成功"); try { System.out.println(threadName+":使当前线程等待,并释放锁资源。"); condition.await(); } catch (InterruptedException e) { e.printStackTrace(); }finally { reentrantLock.unlock(); System.out.println(threadName+":释放锁"); } } /** * 唤醒在该Condition实例等待的线程 */ public void signalAll(){ reentrantLock.lock(); condition.signalAll(); reentrantLock.unlock(); } @Override public void run() { service(); } public static void main(String[] args) { TestReentranLock testReentranLock = new TestReentranLock(); Thread threadA = new Thread(testReentranLock,"线程A"); Thread threadB = new Thread(testReentranLock,"线程B"); Thread threadC = new Thread(testReentranLock,"线程C"); threadA.start(); threadB.start(); threadC.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } testReentranLock.signalAll(); } }
Fair lock execution result:
线程B:尝试获取锁 线程A:尝试获取锁 线程B:获取锁成功 线程C:尝试获取锁 线程B:使当前线程等待,并释放锁资源。 线程A:获取锁成功 线程A:使当前线程等待,并释放锁资源。 线程C:获取锁成功 线程C:使当前线程等待,并释放锁资源。 线程B:释放锁 线程C:释放锁 线程A:释放锁
Unfair lock execution result:
线程B:尝试获取锁 线程A:尝试获取锁 线程A:获取锁成功 线程C:尝试获取锁 线程A:使当前线程等待,并释放锁资源。 线程C:获取锁成功 线程C:使当前线程等待,并释放锁资源。 线程B:获取锁成功 线程B:使当前线程等待,并释放锁资源。 线程A:释放锁 线程B:释放锁 线程C:释放锁
ReadWriteLock interface
//返回用于读取操作的锁. Lock readLock() //返回用于写入操作的锁. Lock writeLock()
ReentrantReadWriteLock class
Construction method
//创建一个ReentrantReadWriteLock实例. ReentrantReadWriteLock() //创建一个具有给定公平策略的ReentrantReadWriteLock实例. ReentrantReadWriteLock(boolean fair)
Common method summary
//返回用于读取操作的锁. Lock ReentrantReadWriteLock。ReadLock。readLock() //返回用于写入操作的锁. Lock ReentrantReadWriteLock。WriteLock。writeLock() //返回等待获取读取或写入锁的线程估计数目. int getQueueLength() //如果此锁的公平设置为 true,则返回 true. boolean isFair() //返回标识此锁及其锁状态的字符串. String toString()
ReadLock/WriteLock static internal class
Common method summary
//试图获取锁. void lock() //如果当前线程未被中断,则获取锁. void lockInterruptibly() //返回绑定到此 Lock 实例的新 Condition 实例. Condition newCondition() //仅在调用时锁为空闲状态才获取该锁. boolean tryLock() //如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁. boolean tryLock(long time, TimeUnit unit) //试图释放锁. void unlock() //返回标识此锁及其锁状态的字符串. String toString()
Because ReadLock does not support conditions, when ReadLock is called The newCondition() method will throw an UnsupportedOperationException exception.
Read locks and write locks using ReentrantReadWriteLock will follow read-read sharing, write-write mutual exclusion, and read-write mutual exclusion.
Usage example:
/** * @Auther: ZHUANGHAOTANG * @Date: 2018/9/26 18:04 * @Description: */ public class TestReentrantReadWriteLock implements Runnable{ private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(true); /** * 读锁 */ private Lock readLock = reentrantReadWriteLock.readLock(); /** * 写锁 */ private Lock writeLock = reentrantReadWriteLock.writeLock(); /** * 读取操作 */ public void reading(){ String threadName = Thread.currentThread().getName(); System.out.println(threadName+":尝试获取读锁"); readLock.lock(); System.out.println(threadName+":获取读锁成功"); System.out.println(threadName+":释放读锁"); readLock.unlock(); } /** * 写入操作 */ public void writing(){ String threadName = Thread.currentThread().getName(); System.out.println(threadName+":尝试获取写锁"); writeLock.lock(); System.out.println(threadName+":获取写锁成功"); System.out.println(threadName+":释放写锁"); writeLock.unlock(); } public static void main(String[] args) { TestReentrantReadWriteLock testReentrantReadWriteLock = new TestReentrantReadWriteLock(); Thread threadA = new Thread(testReentrantReadWriteLock,"线程A"); Thread threadB = new Thread(testReentrantReadWriteLock,"线程B"); Thread threadC = new Thread(testReentrantReadWriteLock,"线程C"); threadA.start(); threadB.start(); threadC.start(); } }
Read shared execution result:
@Overridepublic void run() { //读读共享 reading(); }
线程A:尝试获取读锁 线程B:尝试获取读锁 线程A:获取读锁成功 线程A:释放读锁 线程C:尝试获取读锁 线程C:获取读锁成功 线程C:释放读锁 线程B:获取读锁成功 线程B:释放读锁
The read lock can be acquired by multiple threads at the same time, which can improve the efficiency of reading (although it does not need to be released when only the read lock is used, it will affect the acquisition of the write lock) )
Write-write mutual exclusion execution result:
@Overridepublic void run() { //写写互斥 writing(); }
线程A:尝试获取写锁 线程B:尝试获取写锁 线程A:获取写锁成功 线程C:尝试获取写锁 线程A:释放写锁 线程B:获取写锁成功 线程B:释放写锁 线程C:获取写锁成功 线程C:释放写锁
Write lock can only be locked at the same time Can be obtained by a thread.
Read and write mutual exclusion execution result:
@Overridepublic void run() { //读写互斥 writing(); reading(); }
线程A:尝试获取写锁 线程C:尝试获取写锁 线程B:尝试获取写锁 线程A:获取写锁成功 线程A:释放写锁 线程A:尝试获取读锁 线程C:获取写锁成功 线程C:释放写锁 线程C:尝试获取读锁 线程B:获取写锁成功 线程B:释放写锁 线程B:尝试获取读锁 线程C:获取读锁成功 线程C:释放读锁 线程A:获取读锁成功 线程A:释放读锁 线程B:获取读锁成功 线程B:释放读锁
Cannot write while reading, You cannot read while writing, that is, when acquiring a read lock, if the write lock is currently held by a thread, you will wait for the write lock to be released. When acquiring a write lock, if the read lock is currently held by a thread, you will wait for the read lock to be released and The write lock is not held.
3. Classification of locks in Java
The locks in Java are according to the lock divided by characteristics.
Fair lock/unfair lock
Fair lock: multi-threads apply for locks according to acquire locks in order.
Unfair lock: Multi-threads do not acquire locks in the order in which they apply for locks, that is, the thread with the first lock() is not the first to acquire the lock.
For ReentranLock and ReentrantReadWriteLock locks, you can set whether they are fair locks or unfair locks through the construction method.
#For the Synchronized keyword, it is an unfair lock.
Shared lock/exclusive lock
Shared lock: means that the lock can be held by multiple threads at the same time. For ReadLock, it is shared Lock.
Exclusive lock: means that the lock can only be held by one thread at the same time. For ReentranLock, WriteLock, and Synchronized, it is an exclusive lock.
Optimistic lock/pessimistic lock
Optimistic lock and pessimistic lock are not specific Locking characteristics, but the perspective when looking at concurrency.
Optimistic locking: It is believed that concurrent operations will not affect the integrity of the data, so there is no need to lock.
Pessimistic lock: It is believed that concurrent operations will definitely affect the integrity of the data, so locking must be performed.
The read operation is suitable for optimistic locking, that is, no locking is performed, which can improve the efficiency of reading data.
Write operations are suitable for pessimistic locking, that is, locking must be performed.
Segmented lock
Segmented lock refers to the design of the lock, which controls concurrent operations by refining the granularity of the lock. , the segment in Java's ConcurrentHashMap implements concurrent operations through the design of segment locks.
Bias lock/Lightweight lock/Heavyweight lock
Bias lock, lightweight lock and heavyweight lock are all finger locks The different states are for the Synchronized keyword.
Biased lock: means that the synchronized method or synchronized statement block is always held by only one thread. At this time, the lock status is biased lock, which will reduce the cost of the thread acquiring the lock.
Lightweight lock: When the lock status is biased lock, if it is accessed by other threads, other threads will try to acquire the lock by spinning. The status is lightweight lock.
Spin attempts to acquire the lock by looping a certain number of times. This method does not block the thread. The disadvantage is that it consumes CPU performance.
Heavyweight lock: When the lock status is a lightweight lock, if other threads have not acquired the lock after spinning, then the lock status is a heavyweight lock. This At this time, other threads will enter the blocking state and performance will be reduced.
#When the lock status is biased lock, the performance is the highest, and when the lock is heavyweight, the performance is the lowest.
The above is the detailed content of What is a lock in Java? Detailed introduction to locks in Java. For more information, please follow other related articles on the PHP Chinese website!