Java 5.0 高性能程序开发总结
2013-04-18 20:41
218 查看
一、并发集合类的选择
同步的集合类
例如:
privateAtomicIntegerbomdIdCreator=newAtomicInteger();//自增序列号
publicintgetNewBombID(){
returnbomdIdCreator.addAndGet(1);
}
classX{
privatefinalReentrantLocklock=newReentrantLock();
//...
publicvoidm(){
lock.lock();//blockuntilconditionholds
try{
//...methodbody
}finally{
lock.unlock()
}
}
}
publicclassThreadPoolExecutorTest{
finalstaticExecutorServicethreadPool=Executors.newCachedThreadPool();
//简单线程池实现
publicstaticvoidmain(String[]args){
for(inti=0;i<10;i++){
threadPool.execute(new
Runnable(){
public
voidrun(){
System.out.println("aaa"+this.getClass().getName());
//do
otherthings
}
});
}
}
}
同步的集合类
Hashtable和
Vector,以及同步的包装器类
Collections.synchronizedMap和
Collections.synchronizedList,为
Map和
List提供了基本的有条件的线程安全的实现。然而,某些因素使得它们并不适用于具有高度并发性的应用程序中――它们的集合范围的单锁特性对于可伸缩性来说是一个障碍,而且,很多时候还必须在一段较长的时间内锁定一个集合,以防止出现
ConcurrentModificationExceptions异常。
ConcurrentHashMap和
CopyOnWriteArrayList实现提供了更高的并发性,同时还保住了线程安全性,只不过在对其调用者的承诺上打了点折扣。
ConcurrentHashMap和
CopyOnWriteArrayList并不是在您使用
HashMap或
ArrayList的任何地方都一定有用,但是它们是设计用来优化某些特定的公用解决方案的。许多并发应用程序将从对它们的使用中获得好处。总结:在多线程并发情况下,为了避免
ConcurrentModificationExceptions异常,建议使用
ConcurrentHashMap和
CopyOnWriteArrayList
。
还有下面的几个可以考虑:ConcurrentLinkedQueue、CopyOnWriteArraySet、LinkedBlockingQueue、ArrayBlockingQueue
二、高效的乘除运算
服务器计算时,对于乘除运算,采用下面的方式:
A*2=a<<1
A/2=a>>1
这样可以提高运算效率。
三、原子自增器
多线程环境下,
AtomicInteger
可用在应用程序中(如以原子方式增加的计数器),并且不能用于替换
Integer
。 但是,此类确实扩展了
Number
,允许那些处理基于数字类的工具和实用工具进行统一访问。
例如:
privateAtomicIntegerbomdIdCreator=newAtomicInteger();//自增序列号
publicintgetNewBombID(){
returnbomdIdCreator.addAndGet(1);
}
四、多线程锁机制实现
多线程环境下,为了避免资源竞争,引入了锁机制。一般实现锁机制有下面几种方法:
1.
同步方法、同步块:
synchronized
2.
监视器方法:(
wait
、
notify
和
notifyAll
)
3.ReentrantLock
注意:ReentrantLock是一个可重入的互斥锁
Lock
,它具有与使用
synchronized
方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。
例如:建议总是立即实践,使用
lock
块来调用
try
,在之前
/
之后的构造中,最典型的代码如下:
classX{
privatefinalReentrantLocklock=newReentrantLock();
//...
publicvoidm(){
lock.lock();//blockuntilconditionholds
try{
//...methodbody
}finally{
lock.unlock()
}
}
}
五、线程池的实现方式
DougLea
编写了一个优秀的并发实用程序开放源码库
util.concurrent
,它包括互斥、信号量、诸如在并发访问下执行得很好的队列和散列表之类集合类以及几个工作队列实现。该包中的
ThreadPoolExecutor
类是一种有效的、广泛使用的以工作队列为基础的线程池的正确实现。您无须尝试编写您自己的线程池,这样做容易出错,相反您可以考虑使用
util.concurrent
中的一些实用程序。
线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行集合任务时使用的线程)的方法。
强烈建议程序员使用较为方便的
Executors
工厂方法
Executors.newCachedThreadPool()
(无界线程池,可以进行自动线程回收)、
Executors.newFixedThreadPool(int)
(固定大小线程池)和
Executors.newSingleThreadExecutor()
(单个后台线程),它们均为大多数使用场景预定义了设置。
例如:
publicclassThreadPoolExecutorTest{
finalstaticExecutorServicethreadPool=Executors.newCachedThreadPool();
//简单线程池实现
publicstaticvoidmain(String[]args){
for(inti=0;i<10;i++){
threadPool.execute(new
Runnable(){
public
voidrun(){
System.out.println("aaa"+this.getClass().getName());
//do
otherthings
}
});
}
}
}
六、实现定时任务的几种方式比较
1.
使用原始的
Timer
类
2.ScheduledThreadPoolExecutor
(
JDK 1.5
新增)
3.Quatz
开源项目
从
Java 5.0
开始,
java.util.concurrent
包中增加了一个
ScheduledThreadPoolExecutor
类,用来实现定时任务和线程池的管理,比起
Timer
简陋的实现是要强大得多。利用
ScheduledThreadPoolExecutor
的
scheduleAtFixedRate()
和
scheduleWithFixedDelay()
两个方法就可以实现任务调度的基本功能,从前用
Timer
实现的功能应该要迁移到
scheduleWithFixedDelay()
上了。
注意:
ScheduledThreadPoolExecutor
是实现
ScheduledExecutorService
接口的具体类。
1)publicstaticfinalScheduledExecutorServicescheduledExecutor=Executors.newScheduledThreadPool(2);
2)publicstaticfinalScheduledThreadPoolExecutorscheduledExecutor=newScheduledThreadPoolExecutor(2);
这两种方式是一样的,都是得到一个可调度的线程池。
ScheduledThreadPoolExecutor
与
Timer
的区别:
1.
Timer
的主要方法有:
//
安排在指定的时间执行
voidschedule(TimerTasktask,Datetime)
//
安排在指定的时间开始以
重复的延时
执行
voidschedule(TimerTasktask,DatefirstTime,longperiod)
//
安排在指定的延迟后执行
voidschedule(TimerTasktask,longdelay)
//
安排在指定的延迟后开始以重复的延时执行
voidschedule(TimerTasktask,longdelay,longperiod)
//
安排在指定的时间开始以
重复的速率
执行
voidscheduleAtFixedRate(TimerTasktask,DatefirstTime,longperiod)
//
安排在指定的延迟后开始以重复的速率执行
voidscheduleAtFixedRate(TimerTasktask,longdelay,longperiod)
注:
重复的延时
和
重复的速率
的区别在于,前者是在前一个任务的执行结束后间隔
period
时间再开始下一次执行;而
scheduleAtFixedRate
则是会尽量按照任务的初始时间来按照间隔
period
时间执行。如果一次任务执行由于某些原因被延迟了,用
schedule()
调度的后续任务同样也会被延迟,而用
scheduleAtFixedRate()
则会快速的开始两次或者多次执行,是后续任务的执行时间能够赶上来。
2.
ScheduledThreadPoolExecutor
的主要方法:
//
在指定的延迟后执行
<V>ScheduledFuture<V>schedule(Callable<V>callable,longdelay,TimeUnitunit)
//
在指定的延迟后执行
ScheduledFuture<?>schedule(Runnablecommand,longdelay,TimeUnitunit)
//
在指定的延迟后以固定速率执行
(
类似
Timer.scheduleAtFixedRate())
ScheduledFuture<?>scheduleAtFixedRate(Runnablecommand,longinitialDelay,longperiod,TimeUnitunit)
//
在指定的延迟后以固定间隔执行
(
类似
Timer.schedule())
ScheduledFuture<?>scheduleWithFixedDelay(Runnablecommand,longinitialDelay,longdelay,TimeUnitunit)
比较:
(
1
)
Timer
对调度的支持是基于绝对时间的,因此任务对系统时间的改变是敏感的;而
ScheduledThreadPoolExecutor
支持相对时间。
(
2
)
Timer
使用单线程方式来执行所有的
TimerTask
,如果某个
TimerTask
很耗时则会影响到其他
TimerTask
的执行;而
ScheduledThreadPoolExecutor
则可以构造一个固定大小的线程池来执行任务。
(
3
)
Timer
不会捕获由
TimerTask
抛出的未检查异常,故当有异常抛出时,
Timer
会终止,导致未执行完的
TimerTask
不再执行,新的
TimerTask
也不能被调度;
ScheduledThreadPoolExecutor
对这个问题进行了妥善的处理,不会影响其他任务的执行。
结论:
Timer
有这么多的缺点,如果是使用
JDK1.5
以上的话,应该没什么理由要使用
Timer
来进行调度。
相关文章推荐
- 关于java开发邮件接收程序的一点总结
- 一个java swt桌面程序开发到打包的总结(3)
- 初学两个月java程序开发的总结
- 一个java swt桌面程序开发到打包的总结(1)
- 一个java swt桌面程序开发到打包的总结(1)(收集)
- 【Java开发技术之程序测试】Junit4 新功能学习总结
- 一个java swt桌面程序开发到打包的总结(2)
- 【Java开发技术之程序测试】Junit4 新功能学习总结
- 网易游戏入职作业总结(pre-3)Windows程序开发
- java程序员如何Ant的task开发java程序
- 【Java邮件开发】5.编写一个JavaMail发送邮件的程序
- 2年Java开发工作经验,跳槽之后面试20余家公司的总结
- 浅析java程序中hibernate的应用总结
- 程序开发工具(Java反编译及Linux等)与调试技巧(eclipse,linux)部分数据库插件
- 多线程高性能 7x24小时 Java NewIO 程序 小结
- Java Web 高性能开发, 前端的高性能
- java程序开发学习路线
- java开发规范总结
- meego中dbus服务程序开发的一点总结