每天一学(2)

目录

        1、线程池是如何知道线程任务是否完成

        2、阻塞队列的有界和无界

        3、ConcurrentHashMap底层实现原理

        5、CAS机制

        6、wait 和 notify 为什么要放在 synchronized


        1、线程池是如何知道线程任务是否完成

        线程池内部

        当把任务丢给线程池去执行,调度工作线程, 通过同步调用执行 run () 方法,正常结束, 等待方法返回 直到结束,

        线程外部:  

        线程池提供了isInterrupted() 方法 判断线程池的运行状态 结果是 意味着任务执行完成 submit 方法 通过 future.get() 方法 正常返回 意味着结束 没有返回则一直执行

        引入CountDownLatch计数器 进行倒计时 有两个方法 :

        1、await()阻塞线程

         2、countDown() 进行倒计时,一旦倒计时归零,所有阻塞在await()方法的线程都会被释放

       2、阻塞队列的有界和无界

        阻塞队列是特殊的队列,1、当队列为空,获取队列中元素的消费者线程,它会被阻塞,同时唤醒生产者线程,2、当队列中元素满了,向队列中添加元素的生产者线程,它会被阻塞,同时唤醒消费者线程。

        有界队列: 阻塞队列中容纳的个数是有限的,比如去实例化一个ArrayBlockingList ,可以在构造方法传一个整形的数字,表示基于数组的阻塞队列中,能够容纳的元素个数,称为

        无界队列:就是没有设置固定大小的队列,并不是没有任何限制,而是元素存储量很大。无界队列存在比较大的潜在风险,并发量较大的情况下,线程池中几乎可以无限制的添加任务,容易导致内存溢出。

        3、ConcurrentHashMap底层实现原理

        整体架构:

        jdk1.8 由数组+红黑树+单向链表构成,默认初始化长度16的数组,由于核心仍是hashmap ,必然会存在hash冲突, 所有ConcurrentHashMap采用链式寻址的方式

        解决hash 冲突:当hash冲突比较多的时候,会造成链表长度问题, jdk 1.8 引入红黑树,当数组长度大于64,并且链表长度大于8,单向链表会转化为红黑树。当链表长度小于8,红黑树就会退化为单项链表。

        基本功能:

         在hashmap基础上提供了并发安全的实现,通过对于node节点去加锁,来保证数据更新的安全性。性能方面优化:

        jdk1.8、ConcurrentHashMap 的锁粒度是数组中某一个节点,

        jdk1.7 、锁定的是segment 锁的范围要更大,性能上会更低,

        引入红黑树,降低数据查询的时间复杂度

        当数组长度不够的时候,对数组进行扩容, 引入了多线程并发扩容(多个线程对原始数组进行分片),每个线程负责对一个分片的迁移。

   4、死锁发生的原因 怎么避免

        死锁:多个锁去竞争同一个资源 造成相互等待,如果没有外部干预、将无法往下执行

导致死锁的条件:

  1. 互斥条件 共享资源x和y 只能被一个线程占用
  2. 请求和保持条件 A线程已经取得共享资源x 在等待共享资源y的时候,不释放x
  3. 其他线程不能强行抢占线程A 占有的资源
  4. 循环等待:线程A 等待B占有的资源 B等待A占有的资源

解决死锁:

        通过人工干预来解决, 重启服务、或者kill 掉线程

        破坏其中任意一种 (互斥条件没办法破话) 互斥条件是互斥锁的基本约束

        5、CAS机制

        CAS是java中unsafe类里面的一个方法,全称:Compare and Swap比较并交换

        主要功能: 保证在多线程环境下,对于共享变量修改的一个原子性

        例子: 有一个成员变量state默认值为0 ,定义了一个方法,逻辑为,先判断state是否为0,如果为0 就修改为1,在单线程没有任何问题,多线程下会存在原子性问题。 这是是一个 read -write 操作, 一般解决会在方法 加 synchronized同步锁来解决,但是加锁 会带来性能上的损耗, 所以可以采用CAS机制进行优化。

   6、wait 和 notify 为什么要放在 synchronized

        wait 和notify 为了实现多个线程之间的协调, 阻塞/被唤醒 。他俩必然成对出现,

        要实现多线程之间的通信,除了管道流,只能通过共享变量的方法来实现,A线程修改共享变量s ,线程B 获得修改之后共享变量s的值

        但是多线程本身具有并行执行的特征,同一时刻多个线程可以同步执行,线程B 在访问共享变量之前,必须要知道线程A已经修改过共享变量S, 修改完同时唤醒等待状态下的线程, synchronized可以实现互斥条件,实现条件等待条件唤醒,为了避免wait /notify 错误使用,强制放入同步代码块。

  • 18
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值