Java基础问答:线程专题

Synchronized和ReentrantLock实现原理

synchronized(用来实现互斥锁mutex)
synchronized作用在代码块时,底层是通过monitorenter,monitorexit指令来实现

  • monitorenter:每个对象都有监视锁(monitor),被占用对象就被锁定,线程执行monitorenter尝试获得monitor的所有权。初始monitor的进入数为0,该线程第一次进入置数为1,同一线程可重复进入数+1,其他进程想进入被阻塞直到数为0。
  • monitorexit:指令执行时,monitor进入数字减1,若此时数为0,那线程退出monitor,不再是该monitor的持有者。其他线程可尝试获得权限。

ReentrantLock
基于AQS(AbstractQueueSynchronized)抽象类,里面有两个队列
AQS管理两队列间等待状态-唤醒的工作。

  • 同步队列:双向链表,存储等待状态线程,等待唤醒获取锁
  • 条件队列:单向链表,存储等待状态线程,唤醒后加入同步队列队尾

ReentrantLock实例化AQS抽象类,重写获取和释放锁(tryAcquire,tryRelease)的方式,管理state,实现lock和unlock

除去Synchronized和ReentrantLock,怎么保护线程安全

1.volatile:该关键字为域变量的访问提供了一种免锁机制,相当于告诉jvm该域可能被其他线程更新,每次使用该域都要重新计算
2.原子变量

Java乐观锁和悲观锁,公平锁和非公平锁

  • 悲观锁:总是假设最坏的情况,每次拿数据时防止被人修改都上锁,syn或lock实现
  • 乐观锁:每次拿数据都认为别人不会修改,不上锁
  • 公平锁:每次有线程抢占锁,先检查一边有无等待队列(eg:syn,ReentrantLock)
  • 非公平锁:实现时多次强调随机抢占(ReentrantLock)
    最大区别:新晋获取锁的进程有多次机会去抢占锁,但加入等待队列后和公平锁一致。

线程池

针对问题:程序要创建大量生存期很短暂的线程时,启动新线程成本高(涉及与OS交互),使用线程池能很好的提升性能。
原理:线程池在系统启动时即创建大量空闲线程,程序将一个RunnableCallable对象传给线程池,线程池会启动一个空闲的线程来执行run()call()方法,执行结束后,空闲线程不死亡,而是再次返回线程池等待下次调用
newCachedThreadPool();newFixedThreadPool(int Threads);newSingleExector()
线程池状态(1->2,3->4->5)
1.Running:能接收新提交任务,呢嗯处理阻塞队列中任务
2.ShutDown:关闭状态,不再接收新提交任务
3.Stop:不能接收处理新任务,终端正在处理线程
4.TidYing:若所有任务终止,有效线程数为0,该线程池调用terminated()进入5状态
4.Terminated:什么也不做
线程池大小
分CPU密集型(CPU核心数+1),和IO密集型(2*CPU核心数)
6大参数
1.核心工作线程数(corePoolSize)
2.最大线程数(maximumPoolSize)
3.多余线程存活时间(keepAliveTime)
4.队列(workQueue)
5.线程创建工厂(threadFactory)
6.拒绝策略(handler)
拒绝策略
线存池任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来会采取拒绝策略
AbortPoilcy(丢弃任务,抛出RejectedExecutionException异常)
DiscardPoilcy(丢弃任务,不跑出异常)

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容