多线程控制、同步的几个实用的类

来源:互联网 发布:商超软件排名 编辑:程序博客网 时间:2024/06/05 15:56

多个线程之间的控制,最基本的就是相互之间的wait(),notify()等。其实java.util.concurrent类中已经有了好多同步辅助类,需要的时候感觉还是很好用的。用法整理一下,走起!

1.Semaphore:

就叫它信号量吧。举个栗子就知道它是干啥的了。
new Semaphore(int)。创建了一个自助提款站点,参数代表此站点有几个ATM机。
一个线程来了,调用semaphore.acquire(),占了一个ATM机。又来一个线程来占用ATM... 直到所有ATM都被占用后,再来线程调用semaphore.acquire(),那么这个线程就必须等待。直到其中有一个线程使用完毕,调用semaphore.release(),前面等待的线程才会停止等待,继续执行下去。

测试代码:

private void initSemaphore() throws InterruptedException {        //这里只分配两个信号量,下面三个线程总会有一个抢不到,只能等待其他线程释放掉其信号。        mSemaphore = new Semaphore(2);        for (int i = 0; i < 3; i++) {            final String threadName = i + "";            new Thread() {                @Override                public void run() {                    super.run();                    long l = System.currentTimeMillis();                    try {                        <span style="color:#ff0000;">mSemaphore.acquire();</span>                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    SystemClock.sleep(2000);                    Log.e(TAG, "Thread num is " + threadName + " is run!" + "Wait time:" + (System.currentTimeMillis() - l));                    <span style="color:#ff0000;">mSemaphore.release();</span>                }            }.start();        }        Log.e(TAG, "Threads run over");    }
执行结果:

E/TAG: Threads run overE/TAG: Thread num is 2 is run!Wait time:2000E/TAG: Thread num is 0 is run!Wait time:2001E/TAG: Thread num is 1 is run!Wait time:3999
可以看到,Thread num 为1 的线程运行时间成了4秒,因为它第一次没有抢到信号量,所以要等待其余两个线程释放信号量,它才会继续执行。


2.CountDownLatch

这个和上面那个有点相类似,还是来个栗子:

new CountDownLatch(int)。创建一个旅游活动,参数表示这个活动最少需要多少成员,活动才能顺利进行下去。

某个线程报到(调用countDownLatch.countDown()方法)。当没有达到最低数量要求,一些调用了countDownLatch.await()方法的线程会在此方法等待,直到报到的数量达到最低要求。

测试代码:

private void initCountDownLatch() throws InterruptedException {        mCountDownLatch = new CountDownLatch(3);        long l = System.currentTimeMillis();        for (int i = 0; i < 3; i++) {            final String threadName = i + "";            new Thread() {                @Override                public void run() {                    super.run();                    SystemClock.sleep(2000);                    Log.e(TAG, "Thread num is " + threadName + " is run!");                    <span style="color:#ff0000;">mCountDownLatch.countDown();</span>                }            }.start();        }        <span style="color:#ff0000;">mCountDownLatch.await()</span>;        Log.e(TAG, "Threads run over "+(System.currentTimeMillis()-l));        /*下面的方法        1.当到指定时间后,上面线程没有全部执行完,不再等待。return false;        2.当到指定时间前,上面线程全部执行完了,则不再等待。return true;        3.当被打断,抛异常。        */       // boolean result = mCountDownLatch.await(1000, TimeUnit.MILLISECONDS);        //boolean result = mCountDownLatch.await(4000, TimeUnit.MILLISECONDS);        //Log.e(TAG, "Threads run over result is " + result + " time is " + (System.currentTimeMillis() - l));    }

执行结果:

E/TAG: Thread num is 0 is run!E/TAG: Thread num is 2 is run!E/TAG: Thread num is 1 is run!E/TAG: Threads run over 2021
可以看到,主线程会等待countDown()调用够3次后,await()方法才往下执行。

下面注释的带参数的几个方法意思是:设置等待时间,不管有没达到数量要求,到时间就不再等待。当然,如果没有达到要求会返回false,反之返回true。

下面是参数为4000ms的执行结果:

E/TAG: Thread num is 2 is run!E/TAG: Thread num is 1 is run!E/TAG: Thread num is 0 is run!E/TAG: Threads run over result is true time is 2017
可以看到,当在设置时间前完成,这个参数是没有什么意义的,返回为true。

下面是参数为1000ms的执行结果:

E/TAG: Threads run over result is false time is 1004E/TAG: Thread num is 0 is run!E/TAG: Thread num is 2 is run!E/TAG: Thread num is 1 is run!
可以看到,当在设置时间前没有完成,不再等待,返回为false

3.CyclicBarrier

这个和上面的countDownLatch相似,上面是让某一个线程等待多个线程。这个是多个线程互相等待某一件事发送,才继续下去。
new CyclicBarrier(4):这个意思是,对所有await的调用线程都会等待,直到await的次数达到指定值,此时,所有await的线程立即被唤醒。

测试代码:

 private void initCyclicBarrier() {        mCyclicBarrier = new CyclicBarrier(4);        for (int i = 0; i < 3; i++) {            final String threadName = i + "";            new Thread() {                @Override                public void run() {                    super.run();                    Log.e(TAG, "Thread num is " + threadName + " is wait!");                    try {                       <span style="color:#ff0000;"> int result  = mCyclicBarrier.await();                        //int result = mCyclicBarrier.await(2000, TimeUnit.MILLISECONDS);</span>                       // Log.e(TAG, "Thread num is " + threadName + " is over " + result);                    } catch (InterruptedException e) {                        e.printStackTrace();                    } catch (BrokenBarrierException e) {                        e.printStackTrace();                    } //catch (TimeoutException e) {                      //  e.printStackTrace();                      //  <span style="color:#ff0000;">Log.e(TAG, "TimeoutException");</span>                   // }                }            }.start();        }    }

执行结果:

E/TAG: Thread num is 0 is wait!E/TAG: Thread num is 1 is wait!E/TAG: Thread num is 2 is wait!E/TAG: Thread num is 2 is overE/TAG: Thread num is 0 is overE/TAG: Thread num is 1 is over
可以看到,等3个都await后,才集体被唤醒,执行over。
其中带参数的await方法,是等待超时时间,如果等待超时,直接抛出TimeOutException。

4.Phaser 

算是CountDownLatch和CyclicBarrier 的合体,但也有改进。
举个栗子:一个任务有3个线程去并发执行,这个任务可以分为4个阶段,并且每个阶段结束,才能进行下个阶段。
那么new Phaser(3),就是三个线程并发执行。三个线程执行调用arriveAndAwaitAdvance()方法,这个方法会等待,直到执行arriveAndAwaitAdvance()方法到达3个后(意思就是当前阶段全部结束,可以进行下个阶段了),都被唤醒,继续执行。

测试代码:

private void initPhaser() {        //三个线程来执行        int threads = 3;        //4个阶段        final int phaser = 4;        mPhaser = new Phaser(<span style="color:#ff0000;">threads</span>);        for (int i = 0; i < 3; i++) {            final String threadName = i + "";            new Thread() {                @Override                public void run() {                    super.run();                    for (int phase = 0; phase < phaser; phase++) {                        Log.e(TAG, "Thread num is " + threadName + "phase is " + phase);                        <span style="color:#ff0000;">mPhaser.arriveAndAwaitAdvance();</span>                    }                }            }.start();        }    }

执行结果:

E/TAG: Thread num is 0phase is 0E/TAG: Thread num is 1phase is 0E/TAG: Thread num is 2phase is 0E/TAG: Thread num is 1phase is 1E/TAG: Thread num is 2phase is 1E/TAG: Thread num is 0phase is 1E/TAG: Thread num is 1phase is 2E/TAG: Thread num is 0phase is 2E/TAG: Thread num is 2phase is 2E/TAG: Thread num is 1phase is 3E/TAG: Thread num is 2phase is 3E/TAG: Thread num is 0phase is 3
可以看到,arriveAndAwaitAdvance()方法,在到达设定值之前会一直等待。



0 0
原创粉丝点击