1、简介:“手动”或“链锁定”,synchronized不容易实现,Lock容易,如:您获取节点A的锁定,然后获取节点B,然后释放A并获取C,然后释放B并获得D等。
2、Lock接口实现类: ReentrantLock , ReentrantReadWriteLock.ReadLock , ReentrantReadWriteLock.WriteLock
注意: 不要在try中获取锁,抛异常出导致无法释放。
3、 Lock接口的特性和常见方法
提供的synchronized不具备的主要特性:
1)尝试非阻塞获锁 :尝试获取锁,某一刻成功获取并持有锁
2)能被中断获锁:取到锁线程能响应中断,中断异常抛出,同时锁释放
3)超时获取锁 :超时没获取,则返回
4、Lock接口基本的方法:
void lock():获得锁。如锁不可用,休眠直到获取锁。
void lockInterruptibly():可用立即返回。同上,只是获取中可以中断当前线程
Condition newCondition():获取等待通知组件,该组件和当前锁绑定,当前线程只获得锁,才能调用该组件wait(),调用后释放锁
boolean tryLock():调用时才可获锁。可用返回true;不可用false 。
boolean tryLock(long time, TimeUnit unit):超时则结束,返回false. 可被中断
void unlock():释放锁。
二 Lock接口的实现类:ReentrantLock
ReentrantLock和synchronized关键字一样可以用来实现线程之间同步互斥,但更强大更灵活
线程锁释放,其他线程才执行(执行顺序不确定的)
2.2 Condition接口简介
实现等待/通知机制,newCondition() 方法
灵活性如:多路通知,一个Lock对象中可创建多个Condition实例(即对象监视器),线程对象注册指定Condition中,选择性线程通知
synchronized当于整个Lock对象中只有一个Condition实例,所有线程都注册一个身上。
1)signalAll():唤醒注册Condition中所有等待线程,notifyAll()造成很大的效率问题
2)void await():相当Object类wait
3)boolean await(long time, TimeUnit unit):相当Object类wait(long timeout)
2.3 用单个Condition实现等待/通知机制:UseSingleConditionWaitNotify.java
2.4 公平锁与非公平锁
公平锁 :FIFO先进先出顺序
非公平锁。随机获取锁的、ReentranLock默认非公平锁
final Service service = new Service(false); //true为公平锁,false为非公平锁
三 ReadWriteLock接口的实现类:ReentrantReadWriteLock
ReentrantLock(排他锁)保证线程安全性,但效率低。ReadWriteLock接口的实现类-ReentrantReadWriteLock读写锁解决
维护两个锁,读共享锁,写操作排他锁。分离读写并发性提升。有写就互斥
原文:https://blog.csdn.net/qq_34337272/article/details/79714196
并发问题
并发问题:内存泄漏、上下文切换、死锁还有受限于硬件和软件的资源闲置
多线程:CPU通过给每个线程分配CPU时间片实现伪同时运行,CPU时间片很短很短,给人同时运行的感觉。
一、上下文切换
消耗大量的 CPU 时间,Linux切换时间消耗非常少。
1.让步式:执行线程主动释放CPU,与锁竞争程度成正比,如何避免:减少锁竞争和用CAS算法(无锁)
2.抢占式:时间片用尽而被迫放弃CPU或优先级高线程所抢占,线程数大于CPU可用核心数引起,如何避免:减少线程数和协程
CAS算法(Compare and swap) 无锁实现,多线程间的变量同步,也叫非阻塞同步
ps:独占锁是悲观锁,如synchronized,最坏导致所有需要锁的线程挂起
二、避免死锁
死锁:两个线程互相等待
1.避免一个线程同时获得多个锁
2.避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
3.尝试用定时锁,lock.tryLock(timeout)替代内部锁
4.加锁和解锁必须在一个数据库连接里,否则锁失败