1、复习
2、公平锁与非公平锁
-
按照线程请求并得到锁的时间顺序,能够将锁分为公平锁和非公平锁
-
公平锁:线程获取锁的顺序是按照线程请求锁的时间迟早来进行划分的,也就是知足先到先得的原则;
-
非公平锁:线程在运行时闯入的,并非按照先到先得的原则。
1.Java中两种锁的实现机制
-
Reentrant reentrant = new Reentrant(true)表明公平锁
-
Reentrant reentrant = new Reentrant(false)表明非公平锁
-
-
在没有公平性需求的前提下尽可能使用非公平锁,由于公平锁会带来额外的开销。
3、独占锁和共享锁
-
按照一个资源是否能够同时被多个线程持有,或者只能被一个线程持有,能够分为独占锁和共享锁。ReetrantLock锁是一个独占锁,同一时间只能由一个线程所持有;共享锁能够由多个线程共同 持有,好比:ReadWriteLock.
-
独占锁是一中悲观锁,这种必须先加排他锁才能对资源进行访问,限制了并发性;共享锁是一中乐观锁,这种放宽了加锁的条件,容许多个线程可以同时访问资源。
4、可重入锁
-
定义:当一个线程要获取一个被其余线程占有的独占锁时,该线程会被阻塞,那么当一个线程获取它本身已经获取的锁时是否会被阻塞起来呢?若是不会阻塞就能够称为
可重入锁
-
package com.ruigege.PricipleAnalyzingOfThreadLocalRandom3;
public class Hello {
public static void main(String[] args) {
new Hello().helloB();
}
public synchronized void helloA() {
System.out.println("HelloA");
}
public synchronized void helloB() {
System.out.println("HelloB");
helloA();
}
}
13.1
-
代码解析:hellB方法调用,会先获取得内置锁,而后打印输出,以后调用helloA方法,在调用以前会先获取内置锁,若是内置锁不是可重入的,那么调用线程将会一直阻塞。
-
实际上synchronized内部锁是一个可重入锁,可重入锁的原理是在锁的内部维护一个线程标示,用于标示该锁目前正在被哪一个线程占用,而后关联一个计数器,一开始计数器值为0,说明该锁没有被任何线程占用,当一个线程获取了该锁时,计数器的值会变成1,计数器的值会变成1,这时其余线程再来获取该锁时会发现锁的全部者不是本身而被阻塞挂起。可是当获取了该锁的线程再次得到锁的时候发现锁的拥有者时本身,就会把计算器值+1,当释放锁后计数器-1,当计数器为0的时候,锁里面的线程标示被重置为null,这时候被阻塞的线程会被唤醒来竞争获取该锁。
5、自旋锁
-
因为Java中的线程是与操做系统中的线程一一对应的,因此当一个线程在获取锁(好比独占锁)失败后,会被切换到内核状态而被挂起,当该线程获取到锁时又须要将其切换到内核状态而唤醒该线程。而从用户状态切换到内核状态的开销是比较大的,在必定程度上会影响并发性能,自旋锁则是,当前线程在获取锁的时候,若是发现这个锁已经被其余的锁占用了,他不能立刻阻塞本身,在不放弃CPU使用权的状况下,屡次尝试获取(默认次数10,可使用-XX:PreBlockSpinsh参数设置该值),颇有可能在后面几回尝试中其余线程已经释放了锁,若是尝试指定的次数后仍没有获取到锁则当前线程才会被阻塞挂起,由此看来自旋锁时使用了CPU时间获取线程阻塞与调度的开销,可是颇有可能这些CPU时间白白浪费了。
6、源码:
-
所在包:com.ruigege.OtherFoundationOfConcurrent2
-
https://github.com/ruigege66/ConcurrentJava
-
-
-
欢迎关注微信公众号:傅里叶变换,我的帐号,仅用于技术交流