5.8 作业

目录

1.Synchronized和ReentrantLock的区别?

2.Synchronized底层如何实现?锁升级过程

2.1锁升级过程

3.锁有哪几种分别有什么特点?

4.手写快速排序?多线程快速排序?


1.Synchronized和ReentrantLock的区别?

  1.  synchronized是java关键字,reentrantLock是java的一个类
  2. synchronized只能实现非公平锁,而reentrantLock可以实现公平锁和非公平锁两种
  3. synchronized不能中断一个等待的线程,reentrantLock可以中断线程
  4. synchronized不能设置超时,reentrantLock可以设置超时
  5. synchronized会自动释放锁,而reentrantLock不会自动释放锁,需要手动释放,否则会导致死锁

2.Synchronized底层如何实现?锁升级过程

一、以下列代码为例,说明同步代码块的底层实现原理:

public class SynchronizedDemo {
    public void method() {
        synchronized (this) {
            System.out.println("Method 1 start");
           }
        }
}

查看反编译后结果,如下图:

 可见,synchronized作用在代码块时,它的底层是通过Monitorenter Monitorexit指令来实现的。

 1、monitorenter:

每个对象都是一个监视器锁monitor,当monitor被占用,就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:

如果monitor的进入数位0,则该线程进入monitor,然后讲进入数设置位1,该线程即为monitor的所有者。如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1.如果其他线程已经占有monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。

2、monitorexit:

执行monitorexit的线程必须是object所对应的monitor持有者。指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去尝试获取这个monitor的所有权。

monitorexit指令出现两次,第一次为同步退出释放锁,第二次为发生异步退出释放锁。

2.1锁升级过程

早起Synchronized的底层实现是重量级的,就是它直接去找操作系统去申请锁,它的效率是很低的。

JDK后来对Synchronized锁进行了优化,这样就有了锁升级的概念

锁升级的过程大致是这样的:

new -> 「偏向锁」 -> 「轻量级锁 (自旋锁)」-> 「重量级锁」

就是当JVM检测到不同的竞争状况时,会自动切换到适合的锁实现,这种切换就是锁的升级。

这几个状态会随着竞争情况逐渐升级,这样的目的就是为了提高获取锁和释放锁的效率

3.锁有哪几种分别有什么特点?

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

        偏向锁:当锁不存在竞争的时候,总是由同一个线程获得锁

        轻量级锁:两个线程不存在同时竞争锁,交替执行,用CAS就可以解决,没必要使用重量级锁。

        重量级锁:是一种互斥锁,同一时间,多个线程竞争锁。开销大,会让其他拿不到锁的线程进入阻塞状态。

        锁升级过程:无锁——偏向锁——轻量级锁——重量级锁

  • 可重入锁/非可重入锁

        可重入锁:线程当前已经持有这把锁了,能在不释放这把锁的情况下,再次获取这把锁。

        不可重入锁:线程当前持有这把锁了,如果想再次获取这把锁,必须先释放锁后才能再次尝试获取。

  • 共享锁/独占锁

        共享锁:同一把锁可以被多个线程同时获得

        独占锁:锁同时只能被一个线程获得

  • 公平锁/非公平锁

        公平锁:线程拿不到锁,就进入等待开始排队,先来先得的意思

        非公平锁:忽略排队,直接插队

  • 悲观锁/乐观锁

        悲观锁:每次在读取数据的时候,都认为数据会被修改,每次都会上锁,这样别人想拿这个数据,就会被阻塞。

        乐观锁:每次在读取数据的时候,都认为别人不会修改数据,但是在写数据的时候会判断别人是否修改了数据

  • 自旋锁/非自旋锁

        自旋锁:线程拿不到锁,就不停地尝试获取锁

        非自旋锁:拿不到锁就直接放弃,进行其他逻辑的处理

  • 可中断锁/不可中断锁

4.手写快速排序?多线程快速排序?


/**
* 快速排序
*
* @param a 数组
* @param low 排序的起始位置
* @param high 排序的末尾位置
*/
public static void quickSort(int[] a, int low, int high) {
    if (low > high) { // 递归结束条件
        return;
    }
    int i = low;
    int j = high;
    int base = a[i]; // 选取基数base
 
    while (i < j) {
        while (i < j && a[j] >= base) { // 从右边开始循环地寻找第一个比base小的元素
            j--;
        }
        if (i < j) { // 找到第一个比base小的元素后,则将当前值复制给a[i],将该元素调整至基数的左边
        
            a[i] = a[j];
            i++;
        }
        while (i < j && a[i] < base) { // 从左边循环地寻找第一个比base大的元素
            i++;
        }
        if (i < j) { // 找到第一个比base小的元素后,则将当前值复制给a[j],将该元素调整至基数的右边
            a[j] = a[i];
            j--;
        }
    }
    a[i] = base; // 进行一趟排序后i j两个指针已经重合,再将记录的base赋值给a[i],至此,a[i]左    变的元素都比a[i]小,右边的元素都比a[i]大
    quickSort(a, low, i - 1); // 递归排序左变的子数组
    quickSort(a, i + 1, high); // 递归排序右边的子数组
}

多线程快速排序:

多线程实现快速排序_NickChen_0411的博客-CSDN博客_多线程快排
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值