java并发编程实战-性能与可伸缩性2

1,减少锁的竞争

  1.1,在并发程序中,对可伸缩性的最主要威胁就是独占方式的资源锁

  1.2,有两个因素影响锁上发生竞争的可能性:锁的请求频率,每次持有锁的时间
2,缩小锁的范围(快进快出)
  2.1,通过缩小方法中锁的作用范围,能极大地减少在持有锁时需要执行的指令数量。根据Amdahl定律,这样消除了限制可伸缩的一个因素,因为串行代码的总量减少了
  2.2,在实际情况中,仅当可以将一些大量的计算或阻塞操作从同步代码块中移除时,才应该考虑同步代码块的大小,因为过度的将一个同步快拆解为多个同步快时,反而会对性能提升产生负面影响。如果JVM执行粗粒度化优化操作,那么可能会将分拆的同步快再重新合并起来
3,减小锁的粒度
  3.1,锁分解和锁分段:
    3.1.1,采用多个相互独立的锁来保护独立的状态变量,从而改变这些变量由单个的锁来保护的情况,这些技术能减小锁操作的粒度,并能实现高伸缩性,然而使用的锁越多,那么发生死锁的风险就越高
    3.1.2,可以将锁分解技术进一步扩展为对一组独立对象上的锁进行分解,这种情况被称为锁分段。
    3.1.3,ConcurrentHashMap实现了使用一个包含16个锁的数组,每个锁保护所有散列桶的1/16,能够支持多达16个并发的写入器。
4,避免热点:HashMap中每个插入删除操作都会维护一个计数器,以降低size()方法和isEmpty()方法的开销,这样就使得技术器成了“热点域(HotField)”,在ConcurrentHashMap中采用了分段计数器,每个分段锁维护各自独立的值,从而来降低热点
5,使用一个方式替代堵占锁:如:使用发容器,读写锁,不可变对象以及原子变量
6,检测CPU利用率,
  6.1,如果CPU没有得到充分利用,那么需要找出其中的原因:负载不充足,IO密集,外部限制,锁竞争
  6.2,如果CPU保持忙碌状态,并且总会有可运行的线程在等待CPU,那么当增加更多的处理器时,程序的性能可能会得到提升
7,向对象池说不
  7.1,现在Java的分配操作已经比C语言的malloc调用更快,在HotSpot1.4.x和5.0中,new Object的代码大约只包含10条及其指令
  7.2,通常,对象分配操作的开销比同步开销更低

  7.3,当线程分配新的对象时,基本上不需要在线程之间进行协调,因为对象分配器通常会使用线程本地内存块,所以不需要在堆数据结构上进行同步,但是如果这些线程池从对象池中请求一个对象,那么就需要通过某种同步机制来协调对象池数据结构访问,从而可能使某个线程被阻塞

总结

由于使用线程常常是为了充分利用多个处理器的计算能力,因此在并发程序性能的讨论中,通常更多地将侧重点放在吞吐量和可伸缩性上,而不是服务时间。Amdahl定律告诉我们,程序的可伸缩性取决于在所哟嗲买中必须被串行执行的代码比例。因为Java程序中串行操作的主要来源是独占方式的资源锁,因此通常可以通过以下方式来提升可伸缩性:减少锁的持有时间,降低锁的粒度,以及采用非独占的锁或非阻塞锁来替代独占锁

你可能感兴趣的:(Java并发编程)