Phaser 线程的阶段化处理

在日常生活中。我们做一件事情的时候,习惯把一件事情分为若干个阶段,然后规定每个阶段的任务和完成时间,从而实现阶段化的控制和管理,阶段化处理往往在完成某一项复杂工作时效率很高。
    从JDK1.7版本开始引入类Phaser,它是Java并发库功能强大并且较复杂的一个功能,可以用来完成阶段式的并发执行任务的功能。
    Phaser类直接从Object类继承,它是一个可复用的同步障栅,与CyclicBarrier 和 ConuntDownLatch功能类似,但使用更加灵活。
    类Phaser的4个构成方法:
        1)Phaser()  //对一个Phaser类的实例初始化。
        2)Phaser(int parties)  //指明了要参与到当前Phaser的线程数
        3)Phaser(Phaser parent) //可为当前的Phaser指明一个父Phaser,从而和当前的Phaser构成一个类似于树状的结构。
        4)Phaser(Phaser parent,int parties)  //可以为当前Phaser指明一个父Phaser,从而和当前的Phaser构成一个类似于树状的结构,parties指明了要参与到当前Phaser的线程数。
    Phaser类使用并发任务数进行初始化,任务在Phaser类上可以随时注册,并发任务数也可以动态的增加哈减少。
    Phaser类的使用:
        需要使用类Phaser作为同步障栅的任务首先要注册到Phaser的对象上,注册工作可以在任何时候使用方法register() 或 bulkRegister() 进行,已经注册的任务也可以在达到后通过arriverAndDeregister()方法取消注册。
        不论是任务注册还是取消注册影响的只是内部计数,这种内部计数没有建立任何的内部记录,所以任务无法查询他们自己是否已经注册。
        与CyclicBarrier类似,Phaser可以重复等待,方法arriveAndAwaitAdvance()和Cyclicbarrier.await()方法的功能类似。每一个Phaser的阶段对应有一个阶段号,该阶段号从0开始,当所有的线程到达该Phaser后,
        阶段号增1(当阶段号达到Integer.MAX_VALUE)后,再次增1从0开始。
        
        阶段号的引用使得到达(Arrival)和等待(Waiting)这两种动作可以独立的进行控制。其中,到达动作可以通过方法arrvie()和 arriveAndDeregister()进行记录,这两个方法不会阻塞,都会返回到达的阶段号。
        当最后一个线程到达指定某一的阶段后,可以执行可选的动作(通过重写方法onAdvance()实现,该动作和CyclicBarrier的障栅动作很像,但更灵活)并将阶段号增加。

        另一个是等待动作,方法awaitAdvance()需要一个参数表明到达的阶段号,当阶段号变换到一个新的阶段后返回。与CyclicBarrier的构造方法不同的是,即将等待的线程已经被中断了,方法awaitAdvance()也会继续等待。
        类Phaser在ForkJoinPool的任务执行中也有用到。

        Phaser类具有两种状态,一种是活动状态,另一种状态是终止状态,通过方法isTerminated()可以检查当前的Phaser是否处于终止状态,通过调用方法onAdvance(),并判断该方法的返回值是否为true,可以触发终止状态。
        当取消注册的行为使得注册的线程数为0时,也会出发终止状态。方法为forceTermination()可用于释放等待的线程,并允许这些线程进入终止状态。

        Phaser类可以构造像树状结构的层次来实现分层,一个Phaser类将会有若干个子类,分层后的Phaser类可以减少同步竞争。同步竞争主要来自于注册到Phaser类的大量的线程,频繁的同步竞争将导致系统的性能下降,增加
        操作的开销。
        
        在一个层次化的Phaser树中,子Phaser类的注册和取消注册到它们的父Phaser是自动进行管理的。当一个子Phaser的注册线程数大于0后(如调用Phaser的构造方法,resgister()或bulkRegister()),该子Phaser被注册到父Phaser;
        而当调用方法arriveAndDeregister()导致注册子Phaser的线程变为0时,该子Phaser将从父Phaser中取消注册。
        
        当在Phaser注册的线程调用了同步方法后,这些已注册的任意一个线程都可以监控该Phaser的状态。在任何时候,可以通过方法getRegisteredParties()获取已注册的线程数,可以通过getArriveParties()方法获取到达当前阶段的
        线程数;通过方法getUnarrivedParties()方法获取已注册但未到达当前阶段的线程数,当这些线程到达后,阶段号将增加。
        以上这几个方法都反映当前Phaser的某一时刻的状态,除此之外,也可以通过toString()获取该Phaser的状态。
        总之,当我们把并发的任务分为若干阶段后,使用Phaser类就变得非常有用。

        demo 示例:
            此例分3个阶段完成。
            1)搜索值为20的数组元素。并记录下标
            2)修改为21
            3)输出结果

        //线程服务类
        public class Searcher extends Thread{
            int [] array;
            int begin;
            int end;
            Phaser phaser;
            int findValue;
            List results;
            
            ThreadLocal searcherThread = new ThreadLocal(){
                protected String initialValue(){
                    return getName() +"-"+"服务线程>>>>>>::" ;
                }
            };
            public Searcher(int [] array,int begin,int end, Phaser phaser,int findValue){
                this.array = array;
                this.begin = begin;
                this.end = end;
                this.phaser = phaser;
                this.findValue = findValue;
                results = new ArrayList();
            }
            public void run(){
                //到达当前Phaser,并等待其他线程到达
                phaser.arriveAndAwaitAdvance();
                for(int i = begin;i                     if(array[i]==findValue){
                        results.add(i);
                    }
                }
                System.out.println(searcherThread .get()+ "已经完成了第"+phaser.getPhase()+"阶段的任务");
                phaser.arriveAndAwaitAdvance();
                for(Integer result :results){
                    array[result]++;    
                }
                System.out.println(searcherThread.get() + "已经完成了第"+phaser.getPhase()+"阶段的任务");
                phaser.arriveAndAwaitAdvance();
                System.out.println(searcherThread.get() +"开始第"+phaser.getPhase()+"个阶段。共改变了"+results.size()+"个。");
                //取消注册
                phaser.arriveAndDeregister();
            }
        }
        //启动测试类
        public class Index{
            public static void main(String [] args){
                int datasize = 4000000;
                int nthread;
                int findValue = 20 ;
                int [] bigData = new int[datasize];
                for(int i=0;i                     bigData[i] = (int)(Math.random()*100);
                }
                nthread =Runtime.getRuntime().availableProcessors();
                int [] range = new int [nthread+1];
                int slice = datasize/nthread;
                for(int i =0;i                     range[i] =slice*i;
                    if(range[i]>datasize){
                        range[i] = datasize;
                    }
                }
                Phaser phaser = new Phaser(nthread);
                Thread[] threads = new Thread[nthread];
                for(int i=0;i                     threads[i] = new Searcher(bigData,range[i],range[i+1],phaser,findValue);
                    threads[i].start();
                }
                for(int i=0;i                     try{
                        threads[i].join();
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
                System.out.println("程序结束,phaser的终止状态为:"+ phaser.isTerminated());
            }
        }

运行结果:

Thread-7-服务线程>>>>>>::已经完成了第1阶段的任务
Thread-2-服务线程>>>>>>::已经完成了第1阶段的任务
Thread-5-服务线程>>>>>>::已经完成了第1阶段的任务
Thread-6-服务线程>>>>>>::已经完成了第1阶段的任务
Thread-4-服务线程>>>>>>::已经完成了第1阶段的任务
Thread-3-服务线程>>>>>>::已经完成了第1阶段的任务
Thread-1-服务线程>>>>>>::已经完成了第1阶段的任务
Thread-0-服务线程>>>>>>::已经完成了第1阶段的任务
Thread-7-服务线程>>>>>>::已经完成了第2阶段的任务
Thread-1-服务线程>>>>>>::已经完成了第2阶段的任务
Thread-3-服务线程>>>>>>::已经完成了第2阶段的任务
Thread-5-服务线程>>>>>>::已经完成了第2阶段的任务
Thread-6-服务线程>>>>>>::已经完成了第2阶段的任务
Thread-0-服务线程>>>>>>::已经完成了第2阶段的任务
Thread-2-服务线程>>>>>>::已经完成了第2阶段的任务
Thread-4-服务线程>>>>>>::已经完成了第2阶段的任务
Thread-6-服务线程>>>>>>::开始第3个阶段。共改变了5086个。
Thread-1-服务线程>>>>>>::开始第3个阶段。共改变了4909个。
Thread-2-服务线程>>>>>>::开始第3个阶段。共改变了4999个。
Thread-7-服务线程>>>>>>::开始第3个阶段。共改变了0个。
Thread-3-服务线程>>>>>>::开始第3个阶段。共改变了4896个。
Thread-5-服务线程>>>>>>::开始第3个阶段。共改变了4988个。
Thread-4-服务线程>>>>>>::开始第3个阶段。共改变了4929个。
Thread-0-服务线程>>>>>>::开始第3个阶段。共改变了5037个。
程序结束,phaser的终止状态为:true

 

2)demo 示例:
            模拟参加大学英语四六级考试。到达考场 - 分发试卷 - 收取一部分答题  - 收取第二部分答题 - 考试结束。
            
            //Phaser类  重写onAdvance()方法
            
            public class CustomizedPhaser extends Phaser{
                //onAdvance方法  返回结果时为true时,可以触发终止状态。
                protected boolean onAdvance(int phaser,int registeredParties){
                    if(phaser==0){
                        return prepare();
                    }else if(phaser ==1){
                        return dispatch();
                    }else if(phaser == 2){
                        return collection_test1();
                    }else if(phaser == 3){
                        return collection_test2();
                    }else if(phaser == 4 ){
                        return over();
                    }else{
                        return true;
                    }        
                }
                //准备    
                private boolean prepare(){
                    System.out.println("第" + this.getPhase() + "阶段,"+this.getRegisteredParties() + "个学生准备好了,");
                    return false;
                }
                //分发试卷
                private boolean dispatch(){
                    System.out.println("第" + this.getPhase() + "阶段,开始分发试卷"+this.getRegisteredParties() + "个学生都已经拿到了试卷,");
                    return false;
                }
                //收取第一部分试卷
                private boolean collection_test1(){
                    System.out.println("第" + this.getPhase() + "阶段,测试一部分结束,收取了" + this.getRegisteredParties() + "个学生科目的一答题卡,");
                    return false;
                }
                //收取第二部分试卷
                private boolean collection_test2(){
                    System.out.println("第" + this.getPhase() + "阶段,测试二部分结束,收取了" + this.getRegisteredParties() + "个学生科目的二作文试卷,");
                    return false;
                }
                //结束
                private boolean over(){
                    System.out.println("第"+ this.getPhase() + "阶段,考试结束。");
                    return true;
                }    
            }
            
        //线程类
        public class Tester extends Thread{
            Phaser phaser;
            Tester(Phaser phaser){
                this.phaser = phaser;
            }
            public void run(){
                System.out.println(this.getName() +"已经到达考场。");
                phaser.arriveAndAwaitAdvance();
                System.out.println(this.getName()+ "等待老师分发试卷...");
                phaser.arriveAndAwaitAdvance();
                System.out.println(this.getName() + "正在答试卷一...");
                phaser.arriveAndAwaitAdvance();
                System.out.println(this.getName() + "正在答试卷二...");
                phaser.arriveAndAwaitAdvance();
                System.out.println(this.getName() + "正在等待宣布考试结束...");
                phaser.arriveAndDeregister();
            }
        }
        
        //测试类
        public class Index{
            public static void main(String [] args){
                //考生数量
                int tester_num = 3;
                Phaser phaser = new CustomizedPhaser();
                Thread [] tester = new Thread[tester_num];
                for(int i=0;i                     tester[i] = new Tester(phaser);
                    phaser.register();
                    tester[i].start();
                }
                for(int i=0;i                     try{
                        tester[i].join();
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }    
        }

 

运行结果:

Thread-0已经到达考场。
Thread-2已经到达考场。
Thread-1已经到达考场。
第0阶段,3个学生准备好了,
Thread-1等待老师分发试卷...
Thread-2等待老师分发试卷...
Thread-0等待老师分发试卷...
第1阶段,开始分发试卷3个学生都已经拿到了试卷,
Thread-0正在答试卷一...
Thread-2正在答试卷一...
Thread-1正在答试卷一...
第2阶段,测试一部分结束,收取了3个学生科目的一答题卡,
Thread-0正在答试卷二...
Thread-1正在答试卷二...
Thread-2正在答试卷二...
第3阶段,测试二部分结束,收取了3个学生科目的二作文试卷,
Thread-2正在等待宣布考试结束...
Thread-1正在等待宣布考试结束...
Thread-0正在等待宣布考试结束...
第4阶段,考试结束。

 

 

你可能感兴趣的:(线程的同步障栅,MoreThread,Phaser,线程的阶段化处理)