Java——锁

1. 悲观锁:面对共享数据,每次线程操作时都会上锁,其他线程阻塞。

        Java中的 synchronized 和 ReentrantLock等就是典型的悲观锁,还有一些使用了 synchronized 关键字的容器类如 HashTable 等也是悲观锁的应用。

2. 乐观锁:操作共享数据时不会上锁,会判断一下在此期间是否有其他线程操作此数据。

        乐观锁可以使用版本号机制CAS算法实现。在 Java 语言中 java.util.concurrent.atomic包下的原子类就是使用CAS 乐观锁实现的

 3. 独占锁:一次只被一个线程持有,其他的全阻塞,此线程既可以读也可以写。

 JDK中的synchronizedjava.util.concurrent(JUC)包中Lock的实现类就是独占锁。

4. 共享锁:多个线程持有,若其中一个线程给共享数据加上了共享锁,则其他线程只能读。

在 JDK 中 ReentrantReadWriteLock 就是一种共享锁。

 5.  互斥锁:唯一+排他,某一资源同时只允许一个访问者对其进行访问

6. 读写锁: 相比于互斥锁,并发性更高,每次只有一个写线程,但有多个读线程。

写锁:独占锁,高优先级

读锁:共享锁,低优先级

读写的接口为:ReadWriteLock接口

public interface ReadWriteLock {
    /**
     * 获取读锁
     */
    Lock readLock();

    /**
     * 获取写锁
     */
    Lock writeLock();
}

 7. 公平锁: 队列,先入先出,排队

true为公平锁,默认非公平 

8. 非公平锁

        多个线程并不按照申请锁的顺序,高并发环境下,可能优先级反转或者某线程饥饿

 

 在 java 中 synchronized 关键字是非公平锁,ReentrantLock默认也是非公平锁

9. 可重入锁:(递归锁)

指某一个线程,在外层方法获取了锁以后,在进入内层方法时会自动获取锁。

在 java 中 synchronized ,ReentrantLock也是可重入锁。

优势:避免死锁。

举例:下面这段代码,可重入锁的意思是,一旦某线程获取了A的锁就不同再获取B的锁了,如果不是可重入锁,可能线程1拿到了A的锁,却没有B的锁,B可能也需要A的锁,造成死锁现象(死锁:互斥使用、不可抢占、请求和保持、循环等待)。

public synchronized void mehtodA() throws Exception{
 mehtodB();
}

public synchronized void mehtodB() throws Exception{

}

 10. 自旋锁

线程没有获得锁时自动进行循环,这种会浪费一些资源,目的是为了减少线程被挂起的概率,JDK1.6以后引入了自适应自旋锁。

11. 分段锁

将锁的颗粒度细化。


锁优化 

1. 锁:当多线程操作共享资源时会有“竞态”,为了让这些线程有着先后顺序。

2. Java锁:

        *显式锁(Reentrantlock):必须手动申请lock()和释放unlock()

                ——可中断:对于内置锁,线程拿不到内置锁就会一直等待,除了获取锁没有其他办法能够让其结束等待。

                ——可定时:如果线程在指定的时间内没有获得锁,该方法就会返回false并结束线程等待。

                ——多条件队列:synchronized对应的只有一个条件队列,而ReentrantLock可以有多个条件队列。使用同一把锁的不同的线程可能有不同的条件谓词,如果只有一个条件队列,当某个条件谓词满足时就无法判断该唤醒条件队列里的哪一个线程;但是如果每个条件谓词都有一个单独的条件队列,当某个条件满足时我们就知道应该唤醒对应队列上的线程(内置锁通过Object.notify()或者Object.notifyAll()方法唤醒,显式锁通过Condition.signal()或者Condition.signalAll()方法唤醒)。这就是多个条件队列的好处。

        *隐式锁、内置锁、内部锁(Synchronized):JVM管理

3. 锁优化(Java系统自身完成):

        1)锁消除:JIT 编译器对内部锁的优化

              逃逸分析:是Java针对逃逸对象(定义在方法内的对象,还被方法体外的其他变量引用了,在方法执行完毕时无法GC回收)的分析。

              Java内部通过“逃逸分析”去分析加锁的代码段,看看是否被对个线程使用,若仅被这一个线程用,编译时就不产生 Synchronized 关键字,仅仅生成代码对应的机器码。

        2)锁粗化:避免一个线程反复申请释放锁

              

        3)偏向锁:偏向于第一个拿到这个锁的线程,如果在接下来的运行中,该锁没有被其他线程访问,就不会触发同步。为了避免相同线程在获取同一个锁是产生线程切换和同步操作。

        4)适应锁:在申请锁时,这个锁正在被其他线程所使用,这个线程会进入(暂停(上下文切换消耗资源,适合线程处理时间长的)或忙等(while循环检查所是否被释放)状态)。

4.锁优化(手写代码):

        1)减少临界区范围:减少锁持有时间

        2)减少锁的颗粒度:降低锁的申请频率

        

        3)读写锁:原本是一把操作共享资源的锁,分为读锁+写锁。        


线程池优化 

任务队列:多位乘客

线程池:多位司机,每个接走一个乘客

如何优化:

每个线程有:线程等待时间+线程CPU时间

线程等待时间所占比例越高,需要越多线程(IO操作)。线程 CPU 时间所占比例越高,需要越少线程(CPU密集型)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值