java性能优化笔记 - 02

来源:互联网 发布:php numericvalue 编辑:程序博客网 时间:2024/05/20 23:37

11.使用NIO提升性能(NEW I/O)

与流式I/O不同,NIO是基于块(Block)的,它以块为基本单位处理数据。在NIO中,最为重要的两个组件是缓冲Buffer和通道

Channel。应用程序中不能直接对Channel进行读写操作,而必须通过Buffer来进行。比如,在读一个Channel时候,需要先将

数据读入到相应的Buffer,然后在Buffer中进行读取。

 

12.影响性能的因素

①GC操作是否及时。

②是否有误附加之外的操作。

③创建与销毁时代价是否高昂。

 

13.强引用,软引用(soft),弱引用(weak),虚引用(phantom)

强引用    永不会被GC回收

V

软引用    若GC中所用内存不足,回收

V

弱引用    只要发现弱引用,不管系统堆空间是否足够,都会进行回收。

V

虚引用    随时都可能被垃圾回收器回收

强引用具备以下特点:

①强引用可以直接访问目标对象。

②强引用所指向的对象在任何时候都不会被系统回收。JVM宁愿抛出OOM异常,也不回收强引用所指向的对象。

③强引用可能导致内存泄露。

 

14.有助于改善性能的技巧

①慎用异常  ------ 不要将异常放入到循环中。

②使用局部变量 ------ 调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(stack)中,速度较大,

其它变量,如静态变量,实例变量都在堆(Heap)中创建,速度较慢。

③位运算替换乘除法(注意代码的可维护性)

④一维数组替换二维数组。

⑤提取表达式 ------ 尽可能让程序少做重复的计算,从循环体中提取重复的代码可以有效的提升系统性能。

⑥展开循环 ------ 当性能问题成为系统的主要矛盾时,展开循环。

⑦静态方法替代实例方法 ------ 对于一些工具类,应该使用static方法实现。这样不仅可以加快函数调用的速度,

同时,调用static方法也不需要生成类的实例。比调用实例方法更方便易用。

 

15.并行程序开发及优化

①Future模式

在于除了主函数中的等待时间,并使得原本需要等待的时间段可以用于处理其他的业务逻辑,从而充分利用计

算机资源。

②Master - Worker模式

系统由两类进程协作工作:Master进程和Worker进程。Master进程负责接收和分配任务,Worker进程负责处理

子任务。当各个Worker进程将子任务处理完成后,将结果返回给Master处理,由Master进程作归纳和汇总,从

而得到系统的最终结果。

③Guarded , Suspension模式

当服务进程准备好时才提供服务。可以确保系统仅在有能力处理某个任务时才处理该任务。当系统没有能力处

理这个任务时,它将暂时存储任务信息等待系统空闲。

可以在一定程度上缓解系统的压力,可以将系统的负载在时间轴上均匀的分配,使用该模式后,可以有效降低

系统的瞬时负载,对提高系统的抗压力和稳定性有一定的帮助。

④不变模式

尽可能的去除同步操作,提高并行程序的性能。满足以下两个条件:

1)当对象创建后,其内部状态和数据不再发生任何变化。

2)对象需要被共享,被多线程频繁访问。

JAVA中实现不变模式:

1) 去除setter方法以及所有修改自身属性的方法。

2)将所有属性设置为私用,并用final标记确保其不可修改。

3)确保没有子类可以重载它的行为。

4)有一个可创建完整对象的构造函数。

 

所有元素据类包装类,都是使用不变模式实现的。

 

⑤生产者-消费者模式

对生产者线程和消费者线程进行解耦,优化了系统整体结构。同时,由于缓冲区的作用,允许生产者线程和消费者

线程存在执行上的性能差异,从一定程度上缓解了性能瓶颈对系统性能的影响。

 

线程池的基本功能就是进行线程的复用。

使用线程池后,线程的创建和关闭通常通过线程池维护。线程通常不会因为执行完一次任务而被关闭。

 

16.JDK并发数据结构

适用于串行程序的一些数据结构无法直接在并发环境下工作,因为这些数据结构不是线程安全的。

①并发List

CopyOnWriteArrayList ---> 读不加锁,写加入ReEntrantLock锁。

Vector                             ---> 读写都加锁

 

②并发Map

ConcurrentHashMap是专门为线程并发而设计的HashMap。它的get()操作是无锁的,它的put()

操作的锁粒度又小于同步的HashMap。因此它的整体性能优于同步的HashMap()。

 

③并发Queue

BlockingQueue类最常用在多线程间的数据共享。如果需要高性能的队列,可以使用ConcurrentLinkedQueue

 

17.并发控制方法

①java内存模型与volatile

保存在主内存区中的变量可以被所有线程共享,但一个线程存取另一个线程的参数或局部变量是不可能的,所以

开发人员不必担心局部变量的线程安全问题。

②double和long类型变量的非原子处理,如果一个double或long变量没有声明为volatile,则变量在进行read或

write操作时,主内存把它当作两个32位的read或write操作进行处理。这两个操作在时间上是分开的可能会有其他

操作介于他们之间。因此,在32位系统中,必须对double或long进行同步。

 

声明为volatile的变量可以做以下保证:

1)其他线程对变量的修改,可以即时反映在当前线程中。

2)确保当前线程对volatile变量的修改,能即时写回共享主内存中,并被其他线程所见。

3)使用volatile声明的变量,编译器会保证其有序性。

 

③同步关键字synchronized

1)在wait()过程中,线程会释放对象锁。

2)当等待obj上的线程收到一个obj.notify()时,它就能更新获得obj的独占锁,并继续运行。

④ReentrantLock

在ReentrantLock使用完毕后,务必释放ReentrantLock锁。

 

⑤ReadWriteLock读写锁

在读多写少的场合,使用读写锁可以分离读操作和写操作,使所有读操作间真正并行。因此,能够有效提高系统的并行能力。

 

⑥Semaphore信号量

可以指定多个线程同时访问某一个资源。在构造信号量对象时,必须要指定信号量的准入数,即同时能申请多个许可。

 

⑦ThreadLocal线程局部变量

ThreadLocal完全不提供锁,而使用以空间换时间的手段,为每个线程提供变量的独立副本,以保障线程安全,因此它不是

一种数据共享的解决方案。应该避免将同一个实例设置到不同线程的ThreadLocal中,否则其线程安全性无法保证。

 

 18.“锁”的性能和优化

一般来说,要出现死锁问题需要满足一下条件:

①互斥条件:一个资源每次只能被一个线程使用。

②请求和保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

③不剥夺条件:进程已获得的资源,在未使用完之前不能被强行剥夺。

④循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

1)减少锁持有时间

减少锁的持有时间有助于降低锁冲突的可能性,进而提升系统的并发能力。

2)减少锁粒度

指缩小锁定对象的范围,从而减少锁冲突的可能性,进而提高系统的并发能力。

3)读写分离锁来替换独占锁。

4)锁分离

5)重入锁和内部锁

6)锁粗化

虚拟机在遇到一连串连续的对同一锁不断进行请求和释放的操作时,便会把所有的锁操作整合成对锁的一次请求,从而减

少对锁的请求同步次数。

7)自旋锁

自旋锁可以使线程在没有取得锁时不被挂起而转而去执行一个空循环(即所谓的自旋)。在若干个空循环后,线程如果获得

了锁,则继续执行。若线程依然不能获得锁才会被挂起。使用自旋锁后,线程被挂起的几率相对减少,线程执行的连贯性相

对加强。

8)锁消除

使用锁消除技术可以去掉那些不可能存在多线程访问的锁请求,从而提高系统性能。

9)无锁的并行计算

在CAS算法中,首先是一个无穷循环。在这里,这个无穷循环用于多线程间的冲突处理,即当当前线程受到其它线程

影响而更新失败时,会不停的尝试直到成功。

 

 

 

0 0
原创粉丝点击