记《JAVA并发编程实战》

2018-06-07  本文已影响0人  EmilioWong

前言

多线程是java是一大核心,作为一个java工程师,我以前对于多线程的理解程度不够,使用上也不足。在读《JAVA并发编程实战》后,多了一些理解,特此记下。

对多线程的理解

  1. 多线程与单线程的对比
  1. 多线程带来的风险

安全性

原子性

不可分割的操作。如a++,实际上包含了3个操作:读a,计算a+1,结果赋值给a,因此++并不是一个原子性操作。

竞态条件

最常见的竞态条件就是“先检查后执行”,CAS(CompareAndSet)。在多线程中处理竞态条件需要复合操作,以复合原子性。

锁的重入性

“重入”指的是获取锁的最小粒度是“线程”,而不是“调用”。比如一个线程调用一个方法时,获取锁进入同步块,在这个同步块里调用另一个需要同一个锁的方法时,不会因需要这个已持有的锁而永远等待。

对象的共享

volatile变量

volatile修饰的变量会在每次使用时都去内存读取最新值,而不是使用寄存器里存储的值。

发布与逸出

“发布”指的是使对象能在当前作用域之外被调用。逸出指的是对象被错误发布。开发时需要避免逸出。如在方法里将不想发布的对象设置进传入的参数对象里或者作为返回值返回;一些不对外的方法设置成private。

“除非需要更高的可见性,否则应将所有的域都声明为私有域”是一个良好的编程习惯。

ThreadLocal

ThreadLocal是对可变的单例变量或者全局变量的一个本地副本,通过调用get方法,各线程可持有一个副本,这样这个变量对象就算不是线程安全的,也不影响各线程的运行。

final

final域能确保初始化过程的安全性,从而可以不受限制地访问不可变对象,并在共享这些对象时无须同步。

“除非需要某个域是可变的,否则应将其声明为final域”是一个良好的编程习惯。

如何避免死锁

如何估计线程池大小

在使用线程池的时候,如果线程池过大,那么大量的线程将在相对很少的CPU和内存资源上发生竞争,这不仅会导致更高的内存使用量,而且还可能耗尽资源。如果线程池过小,那么将导致许多空闲的处理器无法执行工作,从而降低吞吐率。
给定下列定义:
Ncpu = number of CPUs
Ucpu = target CPU utilization,0<=Ucpu<=1
W/C = ratio of wait time to compute time
要使处理器达到预期的使用率,线程池的最优大小等于
Nthreads = NcpuUcpu(1+W/C)
可以通过Runtime来获取CPU的数目:
int N_CPU = Runtime.getRuntime().availableProcessors();

上一篇 下一篇

猜你喜欢

热点阅读