多线程

80 阅读2分钟

1 CountDownLatch、CyclicBarrier、Semaphore讲解

  • CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:
    • CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;不能够重用的
    • CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;以重用
  • Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。

参考www.cnblogs.com/dolphin0520…

2 ThreadLocal

项目使用:定义一个ThreadLocal对象,将线程共享变量set到threadLocal中,每个线程都有一份该共享变量副本,存储在ThreadLocal.ThreadLocalMap中,key为threadLocal变量,值为共享变量副本 发送通知时,将通知数据set到ThreadLocal对象中,等事务提交之后再从ThreadLocal对象getAndRemove出来,进行发通知操作。

3 内存泄露

什么情况会发生内存泄露:当前线程一直不结束(线程池),ThreadLocalMap的数据一直不会被回收,而且不手动移除key,就可能导致内存泄露。

JDK设计上如何预防大多数内存泄露:将ThreadLocal.ThreadLocalMap.Entry的key,即ThreadLocal设计为弱引用,弱引用只能存活到下一次垃圾回收。 垃圾回收后key为null,value在下一次ThreadLocalMap调用set,get,remove的时候会被清除。

开发人员使用时如何避免内存泄露:在使用完ThreadLocal时,及时调用它的remove方法清除数据。 zhuanlan.zhihu.com/p/58636499 blog.csdn.net/yanluandai1…

4 线程池使用场景,配置的线程数,怎么确定具体数量

  • MQ消费者线程(可以慢慢执行),核心线程数、最大线程数都是5个,一个线程对应一个mq的topic,像组织、资源变更,组件启动的时候,从线程池中获取线程,执行mq消息消费任务,从阻塞队列获取mq消息。
  • 异步执行线程池(任务比较耗时如导入),核心线程数、最大线程数都是5个,队列长度为10000
  • 导入时,在2的基础上又创建了线程池,按IO密集型任务计算,线程数量设置为核心线程数(cpu核心)的2倍
    • 计算密集型:线程数=CPU核数+1,也可以设置为CPU核数*2
    • IO密集型:线程数=CPU核心数/(1-阻塞系数),阻塞系数一般为0.8~0.9之间

5 对象锁和类锁

  • 对象锁(this):不同实例同时访问同一个加锁的方法时,不会相互影响
  • 类锁(*.class):同一时间只有一个线程可以访问加锁的方法

项目里面锁住静态的logger变量,静态变量只有一份,所以是类锁。