多线程(2)

目录

一、线程死锁

1.1 死锁必要条件

1.2 避免和预防

二、Java中的锁

2.1 公平锁/非公平锁

 2.2 可重入锁

2.3 独享锁/共享锁

2.4 乐观锁/悲观锁

 2.5 分段锁

 2.6 偏向锁/轻量级锁/重量级锁

三、关键字volatile


一、线程死锁

1.1 死锁必要条件

  • 互斥:至少有一个资源是不可共享的,即一次只能被一个线程使用
  • 占有并等待:一个线程至少持有一个资源,并等待获取其他线程持有的资源
  • 非抢占:资源只有被线程显式释放后才能被其他线程获取,不能被强制抢占
  • 循环等待:一组线程形成一个循环,每个线程都在等待下一个线程所持有的资源

1.2 避免和预防

 破坏死锁的必要条件即可

  • 破坏请求与保持条件一次性申请所有的资源
  • 破坏不剥夺条件:占用部分资源的线程进一步申请其他资源时,如果申请不到,主动释放手上占有的资源
  • 破坏循环等待条件:靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放

二、Java中的锁

2.1 公平锁/非公平锁

  • 公平锁:多个线程按照申请锁的顺序来获取锁
  • 非公平锁:多个线程获取锁的顺序并不是按照申请锁的顺序

对于Java ReentrantLock而言,通过构造函数指定该锁是否是公平锁,默认是非公平锁。非公平锁的优点在于吞吐量比公平锁大。

对于Synchronized而言,也是一种非公平锁。由于其不像ReentrantLock是通过AQS来实现线程调度,所以并没有任何方法使其变成公平锁。

 2.2 可重入锁

又名递归锁,是指同一个线程在外层方法获取锁时,在进入内层方法会自动获取锁

ReentrantLock和Synchronized都是可重入锁,可一定程度上避免死锁。

synchronized void setA() throws Exception{
 Thread.sleep(1000);
 setB();
}
synchronized void setB() throws Exception{
 Thread.sleep(1000);
}

上面的代码就是一个可重入锁的一个特点,如果不是可重入锁的话,setB可能不会被当前线程执行,可能造成死锁。

2.3 独享锁/共享锁

也是互斥锁/读写锁的一种广义说法

  • 独享锁:该锁一次只能被一个线程所持有(Synchronized、ReentrantLock)
  • 共享锁:该锁可被多个线程所持有

 Lock的另一个实现类ReadWriteLock,其读锁是共享锁,写锁是独享锁。

该锁的共享锁可保证并发读是非常高效的,读写、写读、写写的过程是互斥的。独享锁与共享锁也是通过AQS来实现的

2.4 乐观锁/悲观锁

并不是指具体的什么类型的锁,而是指看待并发同步的角度。

  • 悲观锁:认为对于同一个数据的并发操作,一定是会发生修改的,哪怕没有修改,也会认为修改。因此对于同一个数据的并发操作,悲观锁采取加锁的形式。悲观的认为,不加锁的并发操作一定会出问题。【利用各种锁】
  • 乐观锁:认为对于同一个数据的并发操作,是不会发生修改的。在更新数据的时候,会采用尝试更新。乐观的认为,不加锁的并发操作是没有事情的。【常采用CAS算法】

悲观锁适合写操作多的场景,乐观锁适合读操作多的场景,不加锁会带来大量的性能提升。

 2.5 分段锁

分段锁是一种锁的设计,并不是具体的一种锁。对于ConcurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效的并发操作。

我们以ConcurrentHashMap来说一下分段锁的含义以及设计思想。ConcurrentHashMap中的分段锁称为Segment,类似于HashMap的结构,即内部拥有一个数组,数组中的每个元素又是一个链表,同时又是一个ReentrantLock(Segment继承了ReentrantLock)

当需要put元素时,并不是对整个hashmap进行加锁,而是先通过hashcode知道他要放在哪个分段中,然后对这个分段进行加锁。所以当多线程put时,只要不是放在同一个分段中,就实现了真正的并行的插入。

 2.6 偏向锁/轻量级锁/重量级锁

这三种锁是指锁的状态,并且是针对Synchronized,通过对象监视器在对象头中的字段来表明。

  • 偏向锁:指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁降低获取锁的代价
  • 轻量级锁:指当锁是偏向锁时被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能
  • 重量级锁:当锁为轻量级锁时,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。

三、关键字volatile

 被比喻成“轻量级的synchronized”

和synchronized不同,volatile是一个变量修饰符,只能用来修饰变量,无法修饰方法及代码块等

被volatile修饰的共享变量,具有以下两点特性:

  • 保证了不同线程对该变量操作的内存可见性
  • 禁止指令重排序

特点:

1、保证可见性

  • 当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
  • 如果我们将变量声明为volatile,这就指示JVM,这个变量是共享且不稳定的,每次使用它都到主存中进行读取。

2、不保证原子性

3、禁止指令重排 

  • 14
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值