在实际工作中,经常遇到在一个多步作业中由于某一步的瓶颈而制约整个作业步骤的情况,要使性能改善,我们需要发挥多线程集中
处理的作用,把较为容易的步骤先作运行产生批量数据,再交给新线程来集中处理较难的一步,这样就节省了略小于(m-1)*N的宝贵时间
。但同时,问题又出现,因为作业本是存在先后顺序的流水式,变为多个子母式并发线程,线程间的同步通信成为了需要解决的一个问题
,好在Java线程中提供了这样的一种机制,下面就通过一个实例谈谈这方面的注意事项。
在本例中,用Thread.sleep(ms)来代替具体的业务过程,整个作业分为三步:step1、step2、step3,后面将通过打印的结果讨论对性能是
否有所改善。
主调度线程:
public class Main extends Thread{
public static void main(String[] args){
PartTwo part2 = new PartTwo();
PartOne part1 = new PartOne(part2);
part1.start();
part2.start();
}
}
//---------------------------------处理简单的步骤step1、step2------------------------------------
public class PartOne extends Thread{
private String[] docIds = new String[100];
private PartTwo part2;
public PartOne(PartTwo p2){
this.part2 = p2;
}
public void run(){
while (true){
long curTime = System.currentTimeMillis();
step1();
step3();
System.out.println("spend time:"+(System.currentTimeMillis()-curTime));
}
}
public void step1(){
long curTime = System.currentTimeMillis();
for (int i=0; i<100; i++){
docIds[i] = String.valueOf(i);
try{
sleep(100);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
System.out.println("step1.."+(System.currentTimeMillis()-curTime));
synchronized (part2){
part2.notifyAll();
}
}
public void step3(){
long curTime = System.currentTimeMillis();
synchronized (part2.finishSem){
try{
part2.finishSem.wait();
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
if (!part2.getStatus()){
System.out.println("step2 fail...");
}else{
for (int i=0; i<100; i++){
try{
sleep(20);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
}
System.out.println("step3..."+(System.currentTimeMillis()-curTime));
}
}
//---------------------集中式处理的线程----------------------------
public class PartTwo extends Thread{
public Object finishSem = new Object();
private boolean status;
public PartTwo(){
}
public void run(){
while (true){
dosome();
}
}
public void dosome(){
long curTime = System.currentTimeMillis();
try{
synchronized (this){
wait();
}
sleep(5000); //dosomething
System.out.println("step2...."+(System.currentTimeMillis()-curTime));
synchronized (finishSem){
status = true;
finishSem.notifyAll();
}
}catch(InterruptedException ie){
status = false;
ie.printStackTrace();
}
}
public boolean getStatus(){
return this.status;
}
}
结论:如果采用流水式作业,T(step1)=10 ms, T(step2)=4000 ms, T(step3)=20 ms, 那么100个任务所需要的时间是:T=100*
(10+4000+20)= 403,000 ms.
在比较实际运行的结果:
step1..10047
step2....15047
step3...7062
spend time:17109
节省的时间为:403000/17109≈23.55倍。
集中式处理后,三个步骤的运行时间图如下:
step1 |======>|
step2 |-------======>|
step3 |------=======>|
Thread技术方面的总结:
wait():使当前线程陷于等待状态,并释放占用的资源,直至另外的线程将它唤醒。
notifyAll():唤醒请求而未分配到该资源的线程,通知它可以运行。
*注:这两个方法都必须在资源同步的状态下才能使用(synchronized),否则会抛出异常。
*一旦主调线程notifyAll,就意味着同时启动了一个等待该资源的线程,而不管主调线程是否已结束。
*在synchronized块中,notifyAll之前,不允许改变向量的值。