悲观锁:线程拿到资源时,就对资源上锁,并在提交后,才释放锁资源,其他线程才能使用资源 常见:synchronized、Lock,行锁,表锁,读锁,写锁等
乐观锁:拿到资源时,在提交之前,其他的锁也可以操作这个资源。当有冲突的时候,并发机制会保留前一个提交,打回后一个提交,让后一个线程重新获取资源后,再操作,然后提交。常见实现方式:版本号控制,CAS(一般情况下是一个自旋操作,即不断的重试)
公平锁FairSync :就是当前资源被加锁后,其他所有请求线程按照请求的先后顺序搁置到queue中,当锁被释放放掉,然后严格的按照先进先出的原则一个一个加锁
非公平锁NonfairSync:尝试给共享资源加锁,如果加锁成功就阻塞其他线程;如果是共享资源上已经被加锁了,这个时候在进入队列的时候还要再判断下资源有没有被释放掉能不能加锁,两次尝试加锁都失败再霸道也没用了,就只能老老实实去队列尾部排队 。ReentrantLock、ReadWriteLock默认都是非公平模式
可重入锁:可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。例如:synchronized,ReentrantLock
非可重入锁:当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞
共享锁(读锁):获得共享锁之后,可以查看但无法修改和删除数据(如果线程T对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加排它锁)
排他锁(写锁,独享锁):获得排他锁后,既能读数据,又能修改数据F(如果线程T对数据A加上排它锁后,则其他线程不能再对A加任何类型的锁)
锁的状态总共有四种:无锁状态、偏向锁、轻量级锁和重量级锁
偏向锁:偏向锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要同步。大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁
轻量级锁: 轻量级锁提升程序同步性能的依据是:对于绝大部分的锁,在整个同步周期内都是不存在竞争的(区别于偏向锁)。这是一个经验数据。如果没有竞争,轻量级锁使用CAS操作避免了使用互斥量的开销,但如果存在锁竞争,除了互斥量的开销外,还额外发生了CAS操作,因此在有竞争的情况下,轻量级锁比传统的重量级锁更慢(核心:被加锁的代码不会发生并发,如果发生并发,那就膨胀成重量级锁)
重量级锁:依赖对象内部的monitor锁来实现的,而monitor又依赖操作系统的MutexLock(互斥锁)来实现的,所以重量级锁也被成为互斥锁 。Synchronized效率低的原因:线程之间的切换这就需要从用户态转换到核心态
过程:
(1)如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者
(2)如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1
(3)如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权
另外:synchronized关键字并非一开始就该对象加上重量级锁,也是从偏向锁,轻量级锁,再到重量级锁的过程