首页 > 其他分享 >面试基础

面试基础

时间:2022-08-13 18:41:07浏览次数:56  
标签:队列 加锁 CAS 基础 面试 任务 线程 执行

synchronized关键字的底层原理:

synchronized关键字与JVM的monitor有关,monitor里面有个计数器,一开始计数器为0。如果一个线程要获取monitor锁,就看看他的计数器是不是0,如果是0的话,

那么就说明没有人加锁,他就可以获取锁,然后对计数器加1.加锁,一般来说一个对象加一把锁。

monitor中有相关指令:monitorenter和monitorexit

这个monitor是个可重入锁。

线程1:

public void myObject{

}

synchronized(myObject){

    //TODO

    synchronized(myObject){

       //TODO

    }

}

如果还有其他线程对被加锁的对象进行修改,此时这个线程被阻塞,等待线程1释放锁。

 

CAS的实现原理:

CAS:compare and set

原理图如下:

 

当多个线程想对一个对象进行修改时,线程会先读取对象当前的值,然后对当前的进行修改完以后,再跟对象进行一次CAS,如果读取的当前值跟对象一致,

就进行修改对象操作,否则重复上述步骤。CAS再底层的硬件级别保证一定是原子的,同一时间只有一个线程可以执行CAS,先比较再设置,其他线程的CAS

同时间去执行的话会失败

 

ConcurrentHashMap实现原理:

HashMap的底层原理(结构)是:

JDK1.8以前,是数组+链表

JDK1.8以后,是数组+链表+红黑树

JDK1.7以前,对map进行分段加锁

把map中的数组拆分成很多段,对每一段进行加锁

JDK1.8以后优化细粒度,一个数组,每个元素进行CAS,如果失败说明有人正在进行操作,此时synchronized对数组元素加锁,链表+红黑树处理对数组每个元素加锁

 

 同一时间,只有一个线程能成功执行CAS操作

 

AQS实现原理:

AQS:abstract queue synchronizer抽象队列同步器

原理图:

 

 

 代码:

ReentrantLock lock = new ReentrantLosk(); //此时new的锁为一个非公平锁

//多个线程过来都尝试

lock.lock();

//TODO

lock.unlock();

在上一个原理图的基础上,此时线程1释放锁并唤醒线程2,在唤醒过程中,来了一个线程3进行加锁

 

并且线程3加锁成功,线程2继续进入等待队列中。

如何变成公平锁呢?在new锁对象的时候,添加参数true-->ReentrantLock(true)

那么此时new的锁为公平锁,所有新加进来的线程都会先看一下等待队列是否有人,有的话则进入等待队列,而不是直接去加锁

 

线程池的底层工作原理:

系统在执行任务的时候,会先创建一个线程池,然后这个线程池中有一定量的线程,用这些线程去执行任务;

ExecutorService threadPool = Executors.newFixedThreadPool(3);  //3对应的参数是corePoolSize

threeadPool.submit(new Callable(){

    //Override

    public void run(){}

});

 

提交任务时,先看一下线程池里的线程数量是否小于corePoolSize,也就是3,如果小于,直接创建一个线程执行任务

执行完任务之后,这个线程不会死掉,他会尝试从一个无界的LinkedBlockingQueue里获取新的任务,如果没有新的任务,此时就会阻塞等待新的任务

 

 持续提交任务,上述流程反复执行,只要线程池的线程数量小于corePoolSize,就会直接创建新线程来执行任务,执行完了就尝试从无界队列中获取任务,知道线程池里有corePoolSize个线程

接着再次提交任务,会发现线程数量已经跟corePoolSize一样大了,此时直接把任务放进队列,线程会争抢获取这个任务执行,如果所有的线程此时都在执行任务,那么这个无界队列里的任务就可能会越来越多

 

标签:队列,加锁,CAS,基础,面试,任务,线程,执行
From: https://www.cnblogs.com/oneJavaWorkerStudy/p/16583764.html

相关文章