JUC多线程面试必问

1.上下文切换

​ 线程在进行交换的时候,线程的状态要保存或加载

2.synchronized

①特性:

​ a.原子性: 执行操作过程无法中断 (synchronized有原子性是与volatile最大区别)

​ b.可见性: 该线程资源状态对于其他线程可见;

​ c.有序性: 按照代码顺序执行

​ d.可重入性: 已锁对象可重复申请锁

②作用位置,锁对应对象

​ a.普通方法 synchronized加锁对象是this

​ b.静态方法 synchronized加锁对象是当前类的class

​ c.同步代码块 synchronized加锁对象是指定内容

③底层原理

​ 获得锁计数器+1;释放锁计数器-1;底层指令是monitorenter和monitorexit

3.死锁

​ 两个或多个线程被永久阻塞;(互相拿着对方的锁;)根本原因是交叉闭环申请;

4.守护线程

只要主线程结束 守护线程也跟着结束

5线程通信 wait notify/condition

线程之间不是独立个体,需要彼此之间通信写作(生产者和消费者问题)

​ ①wait()–让当前线程释放对象锁进入阻塞;

​ ②notify()–唤醒一个正在等待相应对象锁的进程;使其进入就绪队列(从等待到同步队列的过程);获取cpu执限制;

​ ③condition和lock机制;更加面向对象灵活高效;多路通知特性

6.线程安全(集合)

①线程安全的List

​ 推荐 CopyOnWriteArrayList; //Vector和Collections.synchronizedList效率不高

​②线程安全的Set

​ 推荐 CopyOnWriteArraySet;

③线程安全的Map 线程安全的

​ 推荐 ConcurrentHashMap //Hashtable效率较低

7.单例模式 双重检索

懒汉式、饿汉式、双重检索(代码示例如下)

//双重检索;第一次判断是否需要加锁;第二次判断是否需要创建对象;
public class Singleton {
    private Singleton (){}
    private volatile static Singleton  instance;
    public static Singleton  getInstance(){
        if(instance==null){
            synchronized (Singleton .class){
                if(instance==null){
                    instance=new Singleton ();
                }
            }
        }
        return instance;
    }
}

8.重入锁ReentrantLock 自旋 读写锁 与synchronized区别

①a: synchronized式关键字;TeentrantLock是类;

​ b: ReentrantLock灵活实现多路通知;

​ c:底层实现上ReentrantLock使用CAS实现(调用Unsafe和park方法);synchronized是monitor

②自旋锁:

​ 自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。

③读写锁:ReentrantReadWriteLock

特性:读读共享;读写互斥;写写互斥;(写操作占用锁)
适用于高并发场景;

9.阻塞队列 方法:异常,阻塞,null 原理

①概念:

​ 当队列中为空时,从队列中获取元素的操作将被阻塞;当队列满时,向队列中添加元素的操作将被阻塞
②常见方法

  • add/remove

​ 往队列中添加元素 队列如果满了,添加元素会抛异常

​ 如果队列没有满 添加一个元素会返回一个true

​ 从队列头部移除数据 队列为空 抛异常(粗鲁)

  • offer/poll

​ 如果队列满了 返回一个false

​ 获取队列的首元素 如果拿不到 返回null

  • put/take

​ 如果队列满的 插入动作会阻塞

​ 如果队列元素为空 操作会阻塞

③常见队列:
ArrayBlockingQueue(数组实现定长) LinkedBlockingQueue(链表实现变长)
SynchronousQueue:一个不存储元素的阻塞队列,每一个put操作必须等待take操作,否则不能添加元素,适用于传递数据的场景 在一个线程中使用数据传递给另外一个线程

④原理:
ArrayBlockingQueue的put和take使用的是同一把锁,(队列为满或者空的时候)put和take不能同时执行(而****LinkedBlockingQueue的put和take使用的不是同一把锁,put和take能同时执行)

10.CAS 原理,问题ABA 缺点 与synchronized区别

①原理:
a.CAS有三个基本操作数 内存地址V,旧的预期值,要修改的值

b.当要去修改一个值的时候 会去进行一个比较,如果相同才进行置换

②ABA问题**😗*

一个线程a将数值改成了b,接着又改成了a,此时CAS认为是没有变化,其实是已经变化过了,而这个问题的解决方案可以使用版本号version标识;在java5中AtomicStampedReference已解决问题。

11.线程池工作原理 参数 拒绝策略

①概念:
线程池就是提前创建若干个线程,如果有任务需要处理,线程池里的线程就会处理任务,处理完之后线程并不会被销毁,而是等待下一个任务.

②工作原理:

  • a.创建线程池之后 活着的线程数量为0

  • b.当有新的任务来临的时候 做判断

  • 当提交的任务<核心线程数 马上去创建对应的任务个核心线程数

  • 当提交的任务>核心线程数 没有被处理的任务会交给等待队列去排队

  • 如果等待队列满了 当提交的任务<(max线程数+队列大小) 创建非核心线程去处理任务

  • 如果等待队列满了 当提交的任务>(max线程数+队列大小) 线程池会采用拒绝策略

③参数****new ThreadPoolExecutor(核心线程数*;最大线程数;存活时间;默认线程工厂;拒绝策略;*) **

④拒绝策略
a. AbortPolicy(默认)

​ 抛出异常比较粗鲁

​ b. CallerRunsPolicy

让线程池不能处理的任务交给调用线程池的线程来处理 比较有用的一个策略 能最大限度的处理我们的业务

c. DiscardOldestPolicy

抛弃等待最久的任务 关注的是新任务,时效性较好

​ d. DiscardPolicy

丢弃最新任务 关注的是老任务

12.线程池从创建方法

​ ①newFixedThreadPool
​ 创建固定数量线程的线程池 适用于执行长期任务 性能好
​ ②newSingleThreadExecutor
​ 创建单个线程的线程池 任何时候都只有一个线程在执行 能保证任务的有序性
​ ③newCachedThreadPool
​ 创建可扩展的线程池 适用于短时异步任务
​ 问题:前两个堆积请求会耗费非常大的内存,升值OOM,后一个可能创建很多线程;甚至OOM;
所以推荐使用ThreadPoolExecutor自定义参数创建;

13.Runnable和Callable

​ ①是否有返回值
​ ②.是否抛出异常
​ ③落地方法不一样 run call
​ ④Callable计算结果可以复用 调用过程结果没有出来会阻塞

14.JUC工具类

​ ①CyclicBarrier
​ 所有的资源到齐了才能做某件事情
​ ②CountDownLatch
​ 所有相关人员做了某些事情之后 某个人才能做某件事情

15.semaphore

​ Semaphore就是一个信号量,它的作用是限制某段代码块的并发数;目的限制资源访问(状态);

16.volatile

​ volatile修饰的变量对其他线程具备可见性 ( 保证工作内存修改的值会立即被更新到主存)
​ 可以禁止指令重排
​ 可以和CAS结合保证原子性.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值