网站建设服务条款,门户网站建设全包,孝感网站seo,知乎网站建设入门书1.乐观锁vs悲观锁 乐观锁#xff1a;预测该场景中不太会出现锁冲突的情况。#xff08;后续做的工作会更少#xff09; 悲观锁#xff1a;预测该场景非常容易出现锁冲突#xff08;后续做的工作会更多#xff09; 锁冲突#xff1a;多个线程同时尝试去获得同一把锁…1.乐观锁vs悲观锁 乐观锁预测该场景中不太会出现锁冲突的情况。后续做的工作会更少 悲观锁预测该场景非常容易出现锁冲突后续做的工作会更多 锁冲突多个线程同时尝试去获得同一把锁其中一个线程能够获取成功其余线程阻塞等待 乐观锁和悲观锁是在加锁之前对锁冲突概率的预测决定开销的多少
2.重量级锁vs轻量级锁 重量级锁加锁的开销是比较大的花的时间多占用的资源多一个悲观锁很可能就是一个重量级锁不绝对 轻量级锁加锁的开销比较小花的时间少占用的资源少一个乐观锁很可能就是一个轻量级锁不绝对 .重量级和轻量级锁是在加锁之后对锁实践开销的考量
3.读写锁vs互斥锁 互斥锁就是普通的锁没有为读操作和写操作分开加锁synchronized就是互斥锁 读写锁把读操作加锁和写操作加锁分开了 因为多线程同时去读同一个变量不会涉及到线程安全问题 如果两个线程一个线程读加锁另一个线程也是读加锁不会发生锁竞争多线程并发执行的效率就会更高 如果两个线程一个线程写加锁另一个线程也是写加锁会发生锁竞争 如果两个线程一个线程写加锁另一个线程是读加锁会发生锁竞争 在实践开发中读操作的频率往往比写操作的频率高所以通过读写锁可以大大提高程序运行的效率因为在多个线程对同一个变量进行读取操作的时候不会发生锁竞争是并发执行的
4.自旋锁vs挂起等待锁 自旋锁一种典型的轻量级锁的实现方式线程在抢锁失败后会进入阻塞状态要等到获得锁的线程释放锁才能去尝试获取锁而自旋锁会在获取锁失败了以后立即再尝试去获取锁无限循环一直不停的去尝试获取锁这样一旦锁被其他线程释放就能够第一时间获得锁。 优点一旦锁被释放可以第一时间获得锁对比挂起等待锁获得锁的速度会快很多 缺点如果锁被其他线程持有的时间比较久那么就会持续的消耗cpu资源而挂起等待的时间是不消耗cpu的 挂起等待锁是重量级锁的一种典型表现当出现锁冲突的时候会牵扯到内核对于线程的调度使冲突的线程出现挂起阻塞等待
5.公平锁vs非公平锁 假设三个线程A, B,C.A先尝试获取锁,获取成功.然后B再尝试获取锁,获取失败,阻塞等待;然后C也尝试获取锁,C也获取失败,也阻塞等待. 当线程A释放锁的时候,会发生啥呢? 公平锁:遵守先来后到.B比C先来的.当A释放锁的之后,B就能先于C获取到锁 非公平锁:不遵守先来后到.B和C都有可能获取到锁.
6.可重入锁和不可重入锁 有一个线程针对同一个对象连续加锁了两次如果产生了死锁就是不可重入锁如果没有产生死锁就是可重入锁 例子
public synchronized void increase(){synchronized(this){count;}
} 如上述代码调用increase方法后会在同一个线程中对同一个对象进行两次加锁如果是不可重入锁的话在调用increase方法对类对象进行加锁了以后执行increase方法中的程序再对类对象进行加锁就会发生阻塞等待一直要阻塞到第一个对类对象加锁的线程释放锁但要执行完该线程又需要获得锁了以后才能向下执行所以程序就卡在了第二次对类对象加锁这里也就形成了死锁。
死锁的三种经典情况 1.一个线程一把锁但是是不可重入锁该线程针对这个锁连续加锁两次就会出现死锁 2.两个线程两把锁这两把线程先分别获取到一把锁然后再同时尝试获取对方的那把锁
通过下面的代码可以直观的看到该情况
ublic class Demo1 {public static void main(String[] args) {Object blocer1new Object();Object blocer2new Object();Thread t1new Thread(()-{synchronized(blocer1){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized(blocer2){System.out.println(t1线程获取两把锁);}}});Thread t2new Thread(()-{synchronized(blocer2){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized(blocer1){System.out.println(t2线程获取两把锁);}}});t1.start();t2.start();}
} 3.N个线程M把锁N个线程中每个线程都会对多把锁进行加锁而且加的锁是有重复的这样在莫种特殊情况下就会形成死锁
产生死锁的四个必要条件 1.互斥使用一个线程获取到一把锁了以后其他线程就不能去获取这把锁实际使用的锁一般都是互斥的锁的基本特征 2.不可抢占锁只能是持有者主动释放而不是被其他其他线程直接抢走也是锁的基本特征 3.请求和保持当一个线程去尝试获取多把锁在获取第二把锁的时候会保持对第一把锁的获取状态取决于代码结构 4.循环等待t1尝试获取locker2需要t2执行完释放locker2t2尝试获取locker1需要t1执行完释放locker1发生了死循环取决于代码结构
解决死锁的有效方法 解决死锁主要是针对循环等待这方面来进行解决 当每个线程要获取多把锁先针对锁进行编号约定每个线程如果要获取多把锁必须先获取编号小的锁后获取编号大的锁。 只要所有线程加锁的顺序都严格遵守上述顺序就一定不会出现循环等待就解决了死锁
synchronized采用的锁策略 1.即是悲观锁也是乐观锁即是重量级锁也是轻量级锁是自适应的 2.重量级锁部分是根据系统的互斥锁实现的轻量级锁部分是根据自旋锁实现的 3.非公平锁不会遵循先来后到锁释放后那个线程获得锁各凭本事 4.可重入锁同一个线程可以多次获取同一把锁内部会记录哪个线程拿了锁记录引用计数要是是同一个线程拿锁计数器就加一此时该线程要解锁的话计数器就减一直到1计数器为0才真正解锁 5.不是读写锁是普通的互斥锁
synchronized的自适应过程 代码写了一个synchronized之后这里可能会产生一系列的自适应过程无锁-偏向锁-轻量级锁-重量级锁 一开始是无锁的加了synchronized后就对程序加了偏向锁偏向锁不是真的加锁而只是做了一个标记如果有别的线程来竞争锁了才会真的加锁如果没有别的线程竞争就自始至终都不会真的加锁 偏向锁真的加锁以后就是轻量级锁但是后续如果竞争这把锁的线程越来越多了锁冲突更激烈了从轻量级锁升级成了重量级锁